From 4fe0b96f70d5471a1007ce52af1e72fe533d90d7 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Fri, 11 Sep 2015 19:36:58 +0300 Subject: [PATCH] Extract search and replace component --- ...mponentTest.java => EditorSearchTest.java} | 29 +- .../find/FindInEditorMultiCaretTest.java | 36 +- .../highlighting/HighlightUsagesHandler.java | 12 +- .../intellij/find/EditorSearchComponent.java | 878 ------------------ .../intellij/find/EditorSearchSession.java | 576 ++++++++++++ .../src/com/intellij/find/FindUtil.java | 7 +- .../intellij/find/SearchReplaceComponent.java | 772 +++++++++++++++ ...SearchWrapper.java => SearchTextArea.java} | 72 +- .../AddOccurrenceAction.java | 30 +- .../editorHeaderActions/CloseOnESCAction.java | 42 - .../ContextAwareShortcutProvider.java | 26 + .../EditorHeaderAction.java | 40 - .../EditorHeaderSetSearchContextAction.java | 40 + .../EditorHeaderToggleAction.java | 27 +- .../editorHeaderActions/FindAllAction.java | 74 +- .../NextOccurrenceAction.java | 54 +- .../editorHeaderActions/OccurrenceAction.java | 54 ++ .../PrevNextOccurrenceAction.java | 65 ++ .../PrevOccurrenceAction.java | 48 +- .../RemoveOccurrenceAction.java | 27 +- .../ReplaceOnEnterAction.java | 26 - .../RestorePreviousSettingsAction.java | 42 +- .../editorHeaderActions/SelectAllAction.java | 38 +- .../ShowHistoryAction.java | 49 - .../editorHeaderActions/ShowMoreOptions.java | 3 +- .../editorHeaderActions/StatusTextAction.java | 56 ++ .../editorHeaderActions/SwitchToFind.java | 34 +- .../editorHeaderActions/SwitchToReplace.java | 23 +- .../ToggleExceptCommentsAction.java | 20 +- ...ToggleExceptCommentsAndLiteralsAction.java | 20 +- .../ToggleExceptLiteralsAction.java | 20 +- .../ToggleInCommentsAction.java | 20 +- .../ToggleInLiteralsOnlyAction.java | 20 +- .../editorHeaderActions/ToggleMatchCase.java | 20 +- .../editorHeaderActions/ToggleMultiline.java | 26 - .../TogglePreserveCaseAction.java | 29 +- .../find/editorHeaderActions/ToggleRegex.java | 33 +- .../ToggleSelectionOnlyAction.java | 29 +- .../ToggleWholeWordsOnlyAction.java | 31 +- .../find/editorHeaderActions/Utils.java | 18 + .../intellij/find/impl/FindManagerImpl.java | 24 +- .../livePreview/LivePreviewController.java | 6 +- .../editor/actions/IncrementalFindAction.java | 19 +- .../actions/SelectAllOccurrencesAction.java | 2 - .../actions/SelectNextOccurrenceAction.java | 2 - .../SelectOccurrencesActionHandler.java | 2 - 46 files changed, 1992 insertions(+), 1529 deletions(-) rename java/java-tests/testSrc/com/intellij/find/{EditorSearchComponentTest.java => EditorSearchTest.java} (66%) delete mode 100644 platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java create mode 100644 platform/lang-impl/src/com/intellij/find/EditorSearchSession.java create mode 100644 platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java rename platform/lang-impl/src/com/intellij/find/{SearchWrapper.java => SearchTextArea.java} (54%) delete mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/CloseOnESCAction.java create mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/ContextAwareShortcutProvider.java delete mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java create mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderSetSearchContextAction.java create mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/OccurrenceAction.java create mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevNextOccurrenceAction.java delete mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/ReplaceOnEnterAction.java delete mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowHistoryAction.java create mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/StatusTextAction.java delete mode 100644 platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMultiline.java diff --git a/java/java-tests/testSrc/com/intellij/find/EditorSearchComponentTest.java b/java/java-tests/testSrc/com/intellij/find/EditorSearchTest.java similarity index 66% rename from java/java-tests/testSrc/com/intellij/find/EditorSearchComponentTest.java rename to java/java-tests/testSrc/com/intellij/find/EditorSearchTest.java index ee298c7c48e4..adcda7eab66f 100644 --- a/java/java-tests/testSrc/com/intellij/find/EditorSearchComponentTest.java +++ b/java/java-tests/testSrc/com/intellij/find/EditorSearchTest.java @@ -19,7 +19,9 @@ import com.intellij.ide.IdeEventQueue; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; -public class EditorSearchComponentTest extends LightPlatformCodeInsightFixtureTestCase { +import javax.swing.text.JTextComponent; + +public class EditorSearchTest extends LightPlatformCodeInsightFixtureTestCase { private static final String THE_CODE = "public class A {\n" + " //First comment ABC, ABCD, abc\n" + " int ABC = 3;\n" + @@ -34,18 +36,18 @@ public class EditorSearchComponentTest extends LightPlatformCodeInsightFixtureTe myFixture.getEditor().getSelectionModel().setSelection(i, i+key.length()); myFixture.performEditorAction("Find"); IdeEventQueue.getInstance().flushQueue(); - assertEquals(key, getEditorSearchComponent().getSearchTextComponent().getText()); - assertEquals(key, getEditorSearchComponent().getSearchTextComponent().getSelectedText()); - assertEquals(3, getEditorSearchComponent().getSearchTextComponent().getCaretPosition()); + assertEquals(key, getSearchTextComponent().getText()); + assertEquals(key, getSearchTextComponent().getSelectedText()); + assertEquals(3, getSearchTextComponent().getCaretPosition()); assertTrue(getEditorSearchComponent().hasMatches()); IdeFocusManager.findInstance().requestFocus(myFixture.getEditor().getContentComponent(), false); IdeEventQueue.getInstance().flushQueue(); myFixture.performEditorAction("Find"); IdeEventQueue.getInstance().flushQueue(); - assertEquals(key, getEditorSearchComponent().getSearchTextComponent().getText()); - assertEquals(key, getEditorSearchComponent().getSearchTextComponent().getSelectedText()); - assertEquals(key.length(), getEditorSearchComponent().getSearchTextComponent().getCaretPosition()); + assertEquals(key, getSearchTextComponent().getText()); + assertEquals(key, getSearchTextComponent().getSelectedText()); + assertEquals(key.length(), getSearchTextComponent().getCaretPosition()); getEditorSearchComponent().close(); @@ -55,14 +57,17 @@ public class EditorSearchComponentTest extends LightPlatformCodeInsightFixtureTe IdeEventQueue.getInstance().flushQueue(); myFixture.performEditorAction("Find"); IdeEventQueue.getInstance().flushQueue(); - assertEquals(key, getEditorSearchComponent().getSearchTextComponent().getText()); - assertEquals(key, getEditorSearchComponent().getSearchTextComponent().getSelectedText()); - assertEquals(key.length(), getEditorSearchComponent().getSearchTextComponent().getCaretPosition()); + assertEquals(key, getSearchTextComponent().getText()); + assertEquals(key, getSearchTextComponent().getSelectedText()); + assertEquals(key.length(), getSearchTextComponent().getCaretPosition()); } - private EditorSearchComponent getEditorSearchComponent() { - return (EditorSearchComponent)myFixture.getEditor().getHeaderComponent(); + private EditorSearchSession getEditorSearchComponent() { + return EditorSearchSession.get(myFixture.getEditor()); } + private JTextComponent getSearchTextComponent() { + return getEditorSearchComponent().getComponent().getSearchTextComponent(); + } } diff --git a/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java b/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java index 97b7ae708877..65d04a22dfb1 100644 --- a/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java +++ b/java/java-tests/testSrc/com/intellij/find/FindInEditorMultiCaretTest.java @@ -17,9 +17,8 @@ package com.intellij.find; import com.intellij.find.editorHeaderActions.*; import com.intellij.ide.IdeEventQueue; -import com.intellij.openapi.actionSystem.ActionPlaces; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.ide.impl.DataManagerImpl; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.testFramework.fixtures.EditorMouseFixture; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; @@ -138,9 +137,9 @@ public class FindInEditorMultiCaretTest extends LightPlatformCodeInsightFixtureT } private void setTextToFind(String text) { - EditorSearchComponent editorSearchComponent = getEditorSearchComponent(); - assertNotNull(editorSearchComponent); - JTextComponent searchField = editorSearchComponent.getSearchTextComponent(); + EditorSearchSession editorSearchSession = getEditorSearchComponent(); + assertNotNull(editorSearchSession); + JTextComponent searchField = editorSearchSession.getComponent().getSearchTextComponent(); assertNotNull(searchField); for (int i = 0; i <= text.length(); i++) { searchField.setText(text.substring(0, i)); // emulate typing chars one by one @@ -149,25 +148,23 @@ public class FindInEditorMultiCaretTest extends LightPlatformCodeInsightFixtureT } private void nextOccurrence() { - final EditorSearchComponent editorSearchComponent = getEditorSearchComponent(); - executeAction(new NextOccurrenceAction(editorSearchComponent, editorSearchComponent.getSearchTextComponent(), true)); + executeHeaderAction(EditorSearchSession.createNextOccurrenceAction()); } private void prevOccurrence() { - final EditorSearchComponent editorSearchComponent = getEditorSearchComponent(); - executeAction(new PrevOccurrenceAction(editorSearchComponent, editorSearchComponent.getSearchTextComponent())); + executeHeaderAction(EditorSearchSession.createPrevOccurrenceAction()); } private void addOccurrence() { - executeAction(new AddOccurrenceAction(getEditorSearchComponent())); + executeHeaderAction(new AddOccurrenceAction()); } private void removeOccurrence() { - executeAction(new RemoveOccurrenceAction(getEditorSearchComponent())); + executeHeaderAction(new RemoveOccurrenceAction()); } private void allOccurrences() { - executeAction(new SelectAllAction(getEditorSearchComponent())); + executeHeaderAction(new SelectAllAction()); } private void nextOccurrenceFromEditor() { @@ -191,20 +188,21 @@ public class FindInEditorMultiCaretTest extends LightPlatformCodeInsightFixtureT } private void closeFind() { - EditorSearchComponent editorSearchComponent = getEditorSearchComponent(); - executeAction(new CloseOnESCAction(editorSearchComponent, editorSearchComponent.getSearchTextComponent())); + EditorSearchSession editorSearchSession = getEditorSearchComponent(); + editorSearchSession.close(); } - private static void executeAction(EditorHeaderAction action) { - action.actionPerformed(AnActionEvent.createFromInputEvent(action, null, ActionPlaces.EDITOR_TOOLBAR)); + private void executeHeaderAction(AnAction action) { + DataContext context = new DataManagerImpl.MyDataContext(getEditorSearchComponent().getComponent()); + action.actionPerformed(AnActionEvent.createFromDataContext(ActionPlaces.EDITOR_TOOLBAR, null, context)); } private void initFind() { myFixture.performEditorAction("Find"); } - private EditorSearchComponent getEditorSearchComponent() { - return (EditorSearchComponent)myFixture.getEditor().getHeaderComponent(); + private EditorSearchSession getEditorSearchComponent() { + return EditorSearchSession.get(myFixture.getEditor()); } private void init(String text) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java index 72ea8d142091..b19ade8c20e7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java @@ -20,7 +20,7 @@ import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.daemon.impl.IdentifierUtil; import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.injection.InjectedLanguageManager; @@ -56,7 +56,6 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.util.*; public class HighlightUsagesHandler extends HighlightHandlerBase { @@ -192,9 +191,8 @@ public class HighlightUsagesHandler extends HighlightHandlerBase { editor = ((EditorWindow)editor).getDelegate(); } - final JComponent oldHeader = editor.getHeaderComponent(); - if (oldHeader instanceof EditorSearchComponent) { - final EditorSearchComponent oldSearch = (EditorSearchComponent)oldHeader; + EditorSearchSession oldSearch = EditorSearchSession.get(editor); + if (oldSearch != null) { if (oldSearch.hasMatches()) { String oldText = oldSearch.getTextInField(); if (!oldSearch.getFindModel().isRegularExpressions()) { @@ -208,9 +206,7 @@ public class HighlightUsagesHandler extends HighlightHandlerBase { } } - final EditorSearchComponent header = new EditorSearchComponent(editor, project); - header.getFindModel().setRegularExpressions(false); - editor.setHeaderComponent(header); + EditorSearchSession.start(editor, project).getFindModel().setRegularExpressions(false); } public static class DoHighlightRunnable implements Runnable { diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java deleted file mode 100644 index b784613ef57c..000000000000 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ /dev/null @@ -1,878 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.intellij.find; - -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.find.editorHeaderActions.*; -import com.intellij.find.impl.livePreview.LivePreviewController; -import com.intellij.find.impl.livePreview.SearchResults; -import com.intellij.icons.AllIcons; -import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.DefaultCustomComponentAction; -import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; -import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.event.SelectionEvent; -import com.intellij.openapi.editor.event.SelectionListener; -import com.intellij.openapi.editor.impl.EditorHeaderComponent; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.ui.DocumentAdapter; -import com.intellij.ui.LightColors; -import com.intellij.ui.OnePixelSplitter; -import com.intellij.ui.SearchTextField; -import com.intellij.ui.components.JBList; -import com.intellij.ui.components.labels.LinkLabel; -import com.intellij.ui.components.labels.LinkListener; -import com.intellij.ui.components.panels.NonOpaquePanel; -import com.intellij.ui.components.panels.Wrapper; -import com.intellij.ui.speedSearch.SpeedSearchSupply; -import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.text.JTextComponent; -import java.awt.*; -import java.awt.event.*; -import java.util.Arrays; -import java.util.regex.Pattern; - -/** - * @author max, andrey.zaytsev - */ -public class EditorSearchComponent extends EditorHeaderComponent implements DataProvider, SelectionListener, SearchResults.SearchResultsListener { - - private final Project myProject; - - private JPanel myLeftPanel; - private JTextComponent mySearchTextComponent; - private Wrapper mySearchFieldWrapper; - - private JTextComponent myReplaceTextComponent; - private Wrapper myReplaceFieldWrapper; - - - private JPanel myRightPanel; - private ActionToolbarImpl mySearchActionsToolbar1; - private ActionToolbarImpl mySearchActionsToolbar2; - private JLabel myMatchInfoLabel; - private LinkLabel myClickToHighlightLabel; - - private ActionToolbarImpl myReplaceActionsToolbar1; - private ActionToolbarImpl myReplaceActionsToolbar2; - private JPanel myReplaceToolbarWrapper; - - @NotNull - private final Editor myEditor; - - public JTextComponent getSearchTextComponent() { - return mySearchTextComponent; - } - - public JTextComponent getReplaceTextComponent() { - return myReplaceTextComponent; - } - - private final Color myDefaultBackground; - - private final LivePreviewController myLivePreviewController; - private final SearchResults mySearchResults; - - private final FindModel myFindModel; - - public EditorSearchComponent(@NotNull Editor editor, Project project) { - this(editor, project, createDefaultFindModel(project, editor)); - } - - public EditorSearchComponent(@NotNull final Editor editor, final Project project, FindModel findModel) { - myFindModel = findModel; - - myProject = project; - myEditor = editor; - - mySearchResults = new SearchResults(myEditor, myProject); - myLivePreviewController = new LivePreviewController(mySearchResults, this); - - myDefaultBackground = new JTextField().getBackground(); - initUI(); - - new SwitchToFind(this); - new SwitchToReplace(this); - - myFindModel.addObserver(new FindModel.FindModelObserver() { - @Override - public void findModelChanged(FindModel findModel) { - String stringToFind = myFindModel.getStringToFind(); - if (!wholeWordsApplicable(stringToFind)) { - myFindModel.setWholeWordsOnly(false); - } - updateUIWithFindModel(); - updateResults(true); - syncFindModels(FindManager.getInstance(myProject).getFindInFileModel(), myFindModel); - } - }); - - updateUIWithFindModel(); - - if (ApplicationManager.getApplication().isUnitTestMode()) { - initLivePreview(); - } - updateMultiLineStateIfNeed(); - } - - private static FindModel createDefaultFindModel(Project project, Editor editor) { - FindModel findModel = new FindModel(); - findModel.copyFrom(FindManager.getInstance(project).getFindInFileModel()); - if (editor.getSelectionModel().hasSelection()) { - String selectedText = editor.getSelectionModel().getSelectedText(); - if (selectedText != null) { - findModel.setStringToFind(selectedText); - } - } - findModel.setPromptOnReplace(false); - return findModel; - } - - - @Override - @Nullable - public Object getData(@NonNls final String dataId) { - if (SpeedSearchSupply.SPEED_SEARCH_CURRENT_QUERY.is(dataId)) { - return mySearchTextComponent.getText(); - } - if (CommonDataKeys.EDITOR_EVEN_IF_INACTIVE.is(dataId)) { - return myEditor; - } - return null; - } - - @Override - public void searchResultsUpdated(SearchResults sr) { - if (mySearchTextComponent.getText().isEmpty()) { - updateUIWithEmptyResults(); - } else { - int count = sr.getMatchesCount(); - boolean notTooMuch = count <= mySearchResults.getMatchesLimit(); - myMatchInfoLabel.setText(notTooMuch - ? ApplicationBundle.message("editorsearch.matches", count) - : ApplicationBundle.message("editorsearch.toomuch", mySearchResults.getMatchesLimit())); - myClickToHighlightLabel.setVisible(!notTooMuch); - if (notTooMuch) { - if (count > 0) { - setRegularBackground(); - } - else { - setNotFoundBackground(); - } - } - else { - setRegularBackground(); - } - } - myReplaceActionsToolbar1.updateActionsImmediately(); - } - - @Override - public void cursorMoved() { - myReplaceActionsToolbar1.updateActionsImmediately(); - } - - @Override - public void updateFinished() { - } - - - - private void initUI() { - myLeftPanel = new NonOpaquePanel(new BorderLayout()); - myLeftPanel.add(mySearchFieldWrapper = new Wrapper(), BorderLayout.NORTH); - myLeftPanel.add(myReplaceFieldWrapper = new Wrapper(), BorderLayout.CENTER); - - updateSearchComponent(); - updateReplaceComponent(); - initSearchToolbars(); - initReplaceToolBars(); - - Wrapper searchToolbarWrapper1 = new NonOpaquePanel(new BorderLayout()); - searchToolbarWrapper1.add(mySearchActionsToolbar1, BorderLayout.WEST); - Wrapper searchToolbarWrapper2 = new Wrapper(mySearchActionsToolbar2); - mySearchActionsToolbar2.setBorder(JBUI.Borders.emptyLeft(16)); - JPanel searchPair = new NonOpaquePanel(new BorderLayout()).setVerticalSizeReferent(mySearchFieldWrapper); - searchPair.add(searchToolbarWrapper1, BorderLayout.WEST); - searchPair.add(searchToolbarWrapper2, BorderLayout.CENTER); - JLabel closeLabel = new JLabel(null, AllIcons.Actions.Cross, SwingConstants.RIGHT); - closeLabel.setBorder(JBUI.Borders.empty(5)); - closeLabel.setVerticalAlignment(SwingConstants.TOP); - closeLabel.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(final MouseEvent e) { - close(); - } - }); - - closeLabel.setToolTipText("Close search bar (Escape)"); - searchPair.add(new Wrapper.North(closeLabel), BorderLayout.EAST); - - Wrapper replaceToolbarWrapper1 = new Wrapper(myReplaceActionsToolbar1).setVerticalSizeReferent(myReplaceFieldWrapper); - Wrapper replaceToolbarWrapper2 = new Wrapper(myReplaceActionsToolbar2).setVerticalSizeReferent(myReplaceFieldWrapper); - myReplaceActionsToolbar2.setBorder(JBUI.Borders.emptyLeft(16)); - - myReplaceToolbarWrapper = new NonOpaquePanel(new BorderLayout()); - myReplaceToolbarWrapper.add(replaceToolbarWrapper1, BorderLayout.WEST); - myReplaceToolbarWrapper.add(replaceToolbarWrapper2, BorderLayout.CENTER); - - searchToolbarWrapper1.setHorizontalSizeReferent(replaceToolbarWrapper1); - - myRightPanel = new NonOpaquePanel(new BorderLayout()); - myRightPanel.add(searchPair, BorderLayout.NORTH); - myRightPanel.add(myReplaceToolbarWrapper, BorderLayout.CENTER); - - OnePixelSplitter splitter = new OnePixelSplitter(false, .25F); - splitter.setFirstComponent(myLeftPanel); - splitter.setSecondComponent(myRightPanel); - splitter.setHonorComponentsMinimumSize(true); - splitter.setAndLoadSplitterProportionKey("FindSplitterProportion"); - splitter.setOpaque(false); - splitter.getDivider().setOpaque(false); - add(splitter, BorderLayout.CENTER); - } - - private void updateSearchComponent() { - final int oldCaretPosition = mySearchTextComponent != null ? mySearchTextComponent.getCaretPosition() : 0; - boolean wasNull = mySearchTextComponent == null; - String textToSet = myFindModel.getStringToFind(); - if (!updateTextComponent(true)) { - if (!mySearchTextComponent.getText().equals(textToSet)) { - mySearchTextComponent.setText(textToSet); - } - return; - } - - if (!mySearchTextComponent.getText().equals(textToSet)) { - mySearchTextComponent.setText(textToSet); - if (wasNull) { - mySearchTextComponent.selectAll(); - } - } - mySearchTextComponent.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - searchFieldDocumentChanged(); - } - }); - } - }); - - mySearchTextComponent.registerKeyboardAction(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - if (StringUtil.isEmpty(mySearchTextComponent.getText())) { - close(); - } - else { - requestFocus(myEditor.getContentComponent()); - addTextToRecent(EditorSearchComponent.this.mySearchTextComponent); - } - } - }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, SystemInfo.isMac ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK), - JComponent.WHEN_FOCUSED); - if (!wasNull) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - mySearchTextComponent.setCaretPosition(oldCaretPosition); - } - }); - } - - new RestorePreviousSettingsAction(this, mySearchFieldWrapper); - new VariantsCompletionAction(mySearchTextComponent); // It registers a shortcut set automatically on construction - } - - private void searchFieldDocumentChanged() { - setMatchesLimit(LivePreviewController.MATCHES_LIMIT); - String text = mySearchTextComponent.getText(); - myFindModel.setStringToFind(text); - if (!StringUtil.isEmpty(text)) { - updateResults(true); - } - else { - nothingToSearchFor(); - } - if (mySearchTextComponent instanceof JTextArea) { - adjustRows((JTextArea)mySearchTextComponent); - } - updateMultiLineStateIfNeed(); - } - - private void updateMultiLineStateIfNeed() { - myFindModel.setMultiline(mySearchTextComponent.getText().contains("\n") || myReplaceTextComponent.getText().contains("\n")); - } - - - private void updateReplaceComponent() { - final int oldCaretPosition = myReplaceTextComponent != null ? myReplaceTextComponent.getCaretPosition() : 0; - if (!updateTextComponent(false)) { - return; - } - myReplaceTextComponent.setText(myFindModel.getStringToReplace()); - - myReplaceTextComponent.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - replaceFieldDocumentChanged(); - } - }); - } - }); - - if (!getFindModel().isMultiline()) { - new ReplaceOnEnterAction(this, myReplaceTextComponent); - } - - //myReplaceTextComponent.setText(myFindModel.getStringToReplace()); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - myReplaceTextComponent.setCaretPosition(oldCaretPosition); - } - }); - - new VariantsCompletionAction(myReplaceTextComponent); - new NextOccurrenceAction(this, myReplaceFieldWrapper, false); - new PrevOccurrenceAction(this, myReplaceFieldWrapper); - myReplaceFieldWrapper.revalidate(); - myReplaceFieldWrapper.repaint(); - } - - private void replaceFieldDocumentChanged() { - setMatchesLimit(LivePreviewController.MATCHES_LIMIT); - myFindModel.setStringToReplace(myReplaceTextComponent.getText()); - if (myReplaceTextComponent instanceof JTextArea) { - adjustRows((JTextArea)myReplaceTextComponent); - } - updateMultiLineStateIfNeed(); - } - - private void initSearchToolbars() { - DefaultActionGroup actionGroup1 = new DefaultActionGroup("search bar 1", false); - mySearchActionsToolbar1 = (ActionToolbarImpl)ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, actionGroup1, true); - mySearchActionsToolbar1.setForceMinimumSize(true); - mySearchActionsToolbar1.setReservePlaceAutoPopupIcon(false); - mySearchActionsToolbar1.setSecondaryButtonPopupStateModifier(new ActionToolbarImpl.PopupStateModifier() { - @Override - public int getModifiedPopupState() { - return ActionButtonComponent.PUSHED; - } - - @Override - public boolean willModify() { - return myFindModel.getSearchContext() != FindModel.SearchContext.ANY; - } - }); - mySearchActionsToolbar1.setSecondaryActionsTooltip("More Options(" + ShowMoreOptions.SHORT_CUT + ")"); - - - actionGroup1.add(new PrevOccurrenceAction(this, mySearchFieldWrapper)); - actionGroup1.add(new NextOccurrenceAction(this, mySearchFieldWrapper, true)); - actionGroup1.add(new FindAllAction(this)); - actionGroup1.addSeparator(); - actionGroup1.add(new AddOccurrenceAction(this)); - actionGroup1.add(new RemoveOccurrenceAction(this)); - actionGroup1.add(new SelectAllAction(this)); - //actionGroup1.addSeparator(); - //actionGroup1.add(new ToggleMultiline(this));//todo get rid of it! - actionGroup1.addSeparator(); - - actionGroup1.addAction(new ToggleInCommentsAction(this)).setAsSecondary(true); - actionGroup1.addAction(new ToggleInLiteralsOnlyAction(this)).setAsSecondary(true); - actionGroup1.addAction(new ToggleExceptCommentsAction(this)).setAsSecondary(true); - actionGroup1.addAction(new ToggleExceptLiteralsAction(this)).setAsSecondary(true); - actionGroup1.addAction(new ToggleExceptCommentsAndLiteralsAction(this)).setAsSecondary(true); - - DefaultActionGroup actionGroup2 = new DefaultActionGroup("search bar 2", false); - mySearchActionsToolbar2 = (ActionToolbarImpl)ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, actionGroup2, true); - actionGroup2.add(new ToggleMatchCase(this)); - actionGroup2.add(new ToggleRegex(this)); - actionGroup2.add(new ToggleWholeWordsOnlyAction(this)); - - myMatchInfoLabel = new JLabel() { - @Override - public Font getFont() { - Font font = super.getFont(); - return font != null ? font.deriveFont(Font.BOLD) : null; - } - - }; - myMatchInfoLabel.setBorder(JBUI.Borders.empty(2, 20, 0, 20)); - - myClickToHighlightLabel = new LinkLabel("Click to highlight", null, new LinkListener() { - @Override - public void linkSelected(LinkLabel aSource, Object aLinkData) { - setMatchesLimit(Integer.MAX_VALUE); - updateResults(true); - } - }); - myClickToHighlightLabel.setVisible(false); - - mySearchActionsToolbar2 = (ActionToolbarImpl)ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, actionGroup2, true); - actionGroup2.add(new DefaultCustomComponentAction(myMatchInfoLabel)); - actionGroup2.add(new DefaultCustomComponentAction(myClickToHighlightLabel)); - - mySearchActionsToolbar1.setLayoutPolicy(ActionToolbar.AUTO_LAYOUT_POLICY); - mySearchActionsToolbar2.setLayoutPolicy(ActionToolbar.AUTO_LAYOUT_POLICY); - mySearchActionsToolbar1.setBorder(null); - mySearchActionsToolbar2.setBorder(null); - mySearchActionsToolbar1.setOpaque(false); - mySearchActionsToolbar2.setOpaque(false); - - new ShowMoreOptions(mySearchActionsToolbar1, mySearchFieldWrapper); - Utils.setSmallerFontForChildren(mySearchActionsToolbar1); - Utils.setSmallerFontForChildren(mySearchActionsToolbar2); - } - - private void initReplaceToolBars() { - DefaultActionGroup actionGroup1 = new DefaultActionGroup("replace bar 1", false); - myReplaceActionsToolbar1 = (ActionToolbarImpl)ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, actionGroup1, true); - myReplaceActionsToolbar1.setForceMinimumSize(true); - myReplaceActionsToolbar1.setReservePlaceAutoPopupIcon(false); - final JButton myReplaceButton = new JButton("Replace"); - myReplaceButton.setFocusable(false); - myReplaceButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - replaceCurrent(); - } - }); - - final JButton myReplaceAllButton = new JButton("Replace all"); - myReplaceAllButton.setFocusable(false); - myReplaceAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - myLivePreviewController.performReplaceAll(); - } - }); - - final JButton myExcludeButton = new JButton(""); - myExcludeButton.setFocusable(false); - myExcludeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - myLivePreviewController.exclude(); - moveCursor(SearchResults.Direction.DOWN); - } - }); - - if (!UISettings.getInstance().DISABLE_MNEMONICS_IN_CONTROLS) { - myReplaceButton.setMnemonic('p'); - myReplaceAllButton.setMnemonic('a'); - myExcludeButton.setMnemonic('l'); - } - - actionGroup1.addAction(new DefaultCustomComponentAction(myReplaceButton){ - @Override - public void update(AnActionEvent e) { - myReplaceButton.setEnabled(canReplaceCurrent()); - } - }); - actionGroup1.addAction(new DefaultCustomComponentAction(myReplaceAllButton) { - @Override - public void update(AnActionEvent e) { - myReplaceAllButton.setEnabled(mySearchResults != null && mySearchResults.hasMatches()); - } - }); - actionGroup1.addAction(new DefaultCustomComponentAction(myExcludeButton) { - @Override - public void update(AnActionEvent e) { - FindResult cursor = mySearchResults != null ? mySearchResults.getCursor() : null; - myExcludeButton.setEnabled(cursor != null); - myExcludeButton.setText(cursor != null && mySearchResults.isExcluded(cursor) ? "Include" : "Exclude"); - } - }); - - myReplaceActionsToolbar1.setLayoutPolicy(ActionToolbar.AUTO_LAYOUT_POLICY); - myReplaceActionsToolbar1.setBorder(null); - myReplaceActionsToolbar1.setOpaque(false); - DefaultActionGroup actionGroup2 = new DefaultActionGroup("replace bar 2", false); - myReplaceActionsToolbar2 = (ActionToolbarImpl)ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, actionGroup2, true); - actionGroup2.addAction(new TogglePreserveCaseAction(this)); - actionGroup2.addAction(new ToggleSelectionOnlyAction(this)); - myReplaceActionsToolbar2.setLayoutPolicy(ActionToolbar.AUTO_LAYOUT_POLICY); - myReplaceActionsToolbar2.setBorder(null); - myReplaceActionsToolbar2.setOpaque(false); - Utils.setSmallerFontForChildren(myReplaceActionsToolbar1); - Utils.setSmallerFontForChildren(myReplaceActionsToolbar2); - } - - private static void adjustRows(JTextArea area) { - area.setRows(Math.max(2, Math.min(3, StringUtil.countChars(area.getText(),'\n')+1))); - } - - public FindModel getFindModel() { - return myFindModel; - } - - private static void syncFindModels(FindModel to, FindModel from) { - to.setCaseSensitive(from.isCaseSensitive()); - to.setWholeWordsOnly(from.isWholeWordsOnly()); - to.setRegularExpressions(from.isRegularExpressions()); - to.setSearchContext(from.getSearchContext()); - if (from.isReplaceState()) { - to.setPreserveCase(from.isPreserveCase()); - } - } - - public void updateUIWithFindModel() { - boolean needToResetSearchFocus = mySearchTextComponent.hasFocus(); - boolean needToResetReplaceFocus = myReplaceTextComponent.hasFocus(); - updateSearchComponent(); - updateReplaceComponent(); - if (myFindModel.isReplaceState()) { - if (myReplaceFieldWrapper.getParent() == null) { - myLeftPanel.add(myReplaceFieldWrapper, BorderLayout.CENTER); - } - if (myReplaceToolbarWrapper.getParent() == null) { - myRightPanel.add(myReplaceToolbarWrapper, BorderLayout.CENTER); - } - if (needToResetReplaceFocus) { - myReplaceTextComponent.requestFocusInWindow(); - } - } else { - if (myReplaceFieldWrapper.getParent() != null) { - myLeftPanel.remove(myReplaceFieldWrapper); - } - if (myReplaceToolbarWrapper.getParent() != null) { - myRightPanel.remove(myReplaceToolbarWrapper); - } - } - if (needToResetSearchFocus) mySearchTextComponent.requestFocusInWindow(); - mySearchActionsToolbar1.updateActionsImmediately(); - mySearchActionsToolbar2.updateActionsImmediately(); - myReplaceActionsToolbar1.updateActionsImmediately(); - myReplaceActionsToolbar2.updateActionsImmediately(); - myReplaceToolbarWrapper.revalidate(); - revalidate(); - repaint(); - - myLivePreviewController.setTrackingSelection(!myFindModel.isGlobal()); - - } - - private static boolean wholeWordsApplicable(String stringToFind) { - return !stringToFind.startsWith(" ") && - !stringToFind.startsWith("\t") && - !stringToFind.endsWith(" ") && - !stringToFind.endsWith("\t"); - } - - private void setMatchesLimit(int value) { - mySearchResults.setMatchesLimit(value); - } - - private boolean canReplaceCurrent() { - return myLivePreviewController != null && myLivePreviewController.canReplace(); - } - - public void replaceCurrent() { - if (mySearchResults.getCursor() != null) { - myLivePreviewController.performReplace(); - } - } - - public void showHistory(final boolean byClickingToolbarButton, JTextComponent textField) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("find.recent.search"); - FindSettings settings = FindSettings.getInstance(); - String[] recent = textField == mySearchTextComponent ? settings.getRecentFindStrings() : settings.getRecentReplaceStrings(); - final boolean toShowAd = textField == mySearchTextComponent && textField.getText().isEmpty() && FindManager.getInstance(myProject).getPreviousFindModel() != null; - Utils.showCompletionPopup(byClickingToolbarButton ? mySearchActionsToolbar1 : null, - new JBList((Object[])ArrayUtil.reverseArray(recent)), - "Recent " + (textField == mySearchTextComponent ? "Searches" : "Replaces"), - textField, - toShowAd ? RestorePreviousSettingsAction.getAd() : null); - } - - private boolean updateTextComponent(final boolean search) { - JTextComponent oldComponent = search ? mySearchTextComponent : myReplaceTextComponent; - Color oldBackground = oldComponent != null ? oldComponent.getBackground() : null; - Wrapper wrapper = search ? mySearchFieldWrapper : myReplaceFieldWrapper; - boolean multiline = myFindModel.isMultiline(); - if (multiline && oldComponent instanceof JTextArea) return false; - if (!multiline && oldComponent instanceof JTextField) return false; - - final JTextComponent textComponent; - if (multiline) { - textComponent = new JTextArea(); - ((JTextArea)textComponent).setColumns(25); - ((JTextArea)textComponent).setRows(2); - wrapper.setContent(new SearchWrapper(textComponent, new ShowHistoryAction(textComponent, this))); - } - else { - SearchTextField searchTextField = new SearchTextField(true); - searchTextField.setOpaque(false); - textComponent = searchTextField.getTextEditor(); - searchTextField.getTextEditor().setColumns(25); - if (UIUtil.isUnderGTKLookAndFeel()) { - textComponent.setOpaque(false); - } - searchTextField.setHistorySize(20); - searchTextField.setHistory(ContainerUtil.reverse(Arrays.asList(search - ? FindSettings.getInstance().getRecentFindStrings() - : FindSettings.getInstance().getRecentReplaceStrings()))); - textComponent.registerKeyboardAction(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - final String text = textComponent.getText(); - myFindModel.setMultiline(true); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (search) { - mySearchTextComponent.setText(text+"\n"); - } else { - myReplaceTextComponent.setText(text+"\n"); - } - } - }); - } - }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.ALT_DOWN_MASK), JComponent.WHEN_FOCUSED); - wrapper.setContent(searchTextField); - } - - if (search) { - mySearchTextComponent = textComponent; - } else { - myReplaceTextComponent = textComponent; - } - - UIUtil.addUndoRedoActions(textComponent); - Utils.setSmallerFont(textComponent); - - textComponent.putClientProperty("AuxEditorComponent", Boolean.TRUE); - if (oldBackground != null) { - textComponent.setBackground(oldBackground); - } - textComponent.addFocusListener(new FocusListener() { - @Override - public void focusGained(final FocusEvent e) { - textComponent.repaint(); - } - - @Override - public void focusLost(final FocusEvent e) { - textComponent.repaint(); - } - }); - new CloseOnESCAction(this, textComponent); - return true; - } - - private void requestFocus(Component c) { - IdeFocusManager.getInstance(myProject).requestFocus(c, true); - } - - public void searchBackward() { - moveCursor(SearchResults.Direction.UP); - addTextToRecent(mySearchTextComponent); - } - - public void searchForward() { - moveCursor(SearchResults.Direction.DOWN); - addTextToRecent(mySearchTextComponent); - } - - public void addTextToRecent(JTextComponent textField) { - final String text = textField.getText(); - if (text.length() > 0) { - if (textField == mySearchTextComponent) { - FindSettings.getInstance().addStringToFind(text); - if (mySearchFieldWrapper.getTargetComponent() instanceof SearchTextField) { - ((SearchTextField)mySearchFieldWrapper.getTargetComponent()).addCurrentTextToHistory(); - } - } else { - FindSettings.getInstance().addStringToReplace(text); - if (myReplaceFieldWrapper.getTargetComponent() instanceof SearchTextField) { - ((SearchTextField)myReplaceFieldWrapper.getTargetComponent()).addCurrentTextToHistory(); - } - } - } - } - - @Override - public void selectionChanged(SelectionEvent e) { - updateResults(false); - } - - private void moveCursor(SearchResults.Direction direction) { - myLivePreviewController.moveCursor(direction); - } - - @Override - public void requestFocus() { - mySearchTextComponent.setSelectionStart(0); - mySearchTextComponent.setSelectionEnd(mySearchTextComponent.getText().length()); - requestFocus(mySearchTextComponent); - } - - public void close() { - IdeFocusManager.getInstance(myProject).requestFocus(myEditor.getContentComponent(), false); - - myLivePreviewController.dispose(); - myEditor.setHeaderComponent(null); - } - - @Override - public void addNotify() { - super.addNotify(); - initLivePreview(); - } - - private void initLivePreview() { - myLivePreviewController.on(); - - myLivePreviewController.setUserActivityDelay(0); - updateResults(false); - myLivePreviewController.setUserActivityDelay(LivePreviewController.USER_ACTIVITY_TRIGGERING_DELAY); - - mySearchResults.addListener(this); - } - - @Override - public void removeNotify() { - super.removeNotify(); - - myLivePreviewController.off(); - mySearchResults.removeListener(this); - - addTextToRecent(mySearchTextComponent); - if (myReplaceTextComponent != null) { - addTextToRecent(myReplaceTextComponent); - } - } - - private void updateResults(final boolean allowedToChangedEditorSelection) { - final String text = myFindModel.getStringToFind(); - if (text.length() == 0) { - nothingToSearchFor(); - } - else { - - if (myFindModel.isRegularExpressions()) { - try { - Pattern.compile(text); - } - catch (Exception e) { - setNotFoundBackground(); - myClickToHighlightLabel.setVisible(false); - mySearchResults.clear(); - myMatchInfoLabel.setText("Incorrect regular expression"); - return; - } - } - - - final FindManager findManager = FindManager.getInstance(myProject); - if (allowedToChangedEditorSelection) { - findManager.setFindWasPerformed(); - FindModel copy = new FindModel(); - copy.copyFrom(myFindModel); - copy.setReplaceState(false); - findManager.setFindNextModel(copy); - } - if (myLivePreviewController != null) { - myLivePreviewController.updateInBackground(myFindModel, allowedToChangedEditorSelection); - } - } - } - - private void nothingToSearchFor() { - updateUIWithEmptyResults(); - if (mySearchResults != null) { - mySearchResults.clear(); - } - } - - private void updateUIWithEmptyResults() { - setRegularBackground(); - myMatchInfoLabel.setText(""); - myClickToHighlightLabel.setVisible(false); - } - - private void setRegularBackground() { - mySearchTextComponent.setBackground(myDefaultBackground); - } - - private void setNotFoundBackground() { - mySearchTextComponent.setBackground(LightColors.RED); - } - - public String getTextInField() { - return mySearchTextComponent.getText(); - } - - public void setTextInField(final String text) { - mySearchTextComponent.setText(text); - myFindModel.setStringToFind(text); - } - - public boolean hasMatches() { - return mySearchResults != null && mySearchResults.hasMatches(); - } - - @Override - public Insets getInsets() { - Insets insets = super.getInsets(); - if (UIUtil.isUnderGTKLookAndFeel() || UIUtil.isUnderNimbusLookAndFeel()) { - insets.top += 1; - insets.bottom += 2; - } - return insets; - } - - public void selectAllOccurrences() { - FindUtil.selectSearchResultsInEditor(myEditor, mySearchResults.getOccurrences().iterator(), -1); - } - - public void removeOccurrence() { - mySearchResults.prevOccurrence(true); - } - - public void addNextOccurrence() { - mySearchResults.nextOccurrence(true); - } - - public void clearUndoInTextFields() { - UIUtil.resetUndoRedoActions(mySearchTextComponent); - UIUtil.resetUndoRedoActions(myReplaceTextComponent); - } -} diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchSession.java b/platform/lang-impl/src/com/intellij/find/EditorSearchSession.java new file mode 100644 index 000000000000..d3ac3f723c29 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchSession.java @@ -0,0 +1,576 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.find; + +import com.intellij.find.editorHeaderActions.*; +import com.intellij.find.impl.livePreview.LivePreviewController; +import com.intellij.find.impl.livePreview.SearchResults; +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.openapi.actionSystem.ex.DefaultCustomComponentAction; +import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.event.SelectionEvent; +import com.intellij.openapi.editor.event.SelectionListener; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.BooleanGetter; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.components.labels.LinkLabel; +import com.intellij.ui.components.labels.LinkListener; +import com.intellij.util.ObjectUtils; +import com.intellij.util.ui.update.Activatable; +import com.intellij.util.ui.update.UiNotifyConnector; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.text.JTextComponent; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.regex.Pattern; + +/** + * @author max, andrey.zaytsev + */ +public class EditorSearchSession implements DataProvider, + SelectionListener, + SearchResults.SearchResultsListener, + SearchReplaceComponent.Listener { + public static DataKey SESSION_KEY = DataKey.create("EditorSearchSession"); + + private final Editor myEditor; + private final LivePreviewController myLivePreviewController; + private final SearchResults mySearchResults; + private final FindModel myFindModel; + private final SearchReplaceComponent myComponent; + + private final LinkLabel myClickToHighlightLabel = new LinkLabel("Click to highlight", null, new LinkListener() { + @Override + public void linkSelected(LinkLabel aSource, Object aLinkData) { + setMatchesLimit(Integer.MAX_VALUE); + updateResults(true); + } + }); + + public EditorSearchSession(@NotNull Editor editor, Project project) { + this(editor, project, createDefaultFindModel(project, editor)); + } + + public EditorSearchSession(@NotNull final Editor editor, Project project, FindModel findModel) { + myClickToHighlightLabel.setVisible(false); + + myFindModel = findModel; + + myEditor = editor; + + mySearchResults = new SearchResults(myEditor, project); + myLivePreviewController = new LivePreviewController(mySearchResults, this); + + myComponent = SearchReplaceComponent + .buildFor(project, myEditor.getContentComponent()) + .addPrimarySearchActions(createPrevOccurrenceAction(), + createNextOccurrenceAction(), + new FindAllAction(), + new Separator(), + new AddOccurrenceAction(), + new RemoveOccurrenceAction(), + new SelectAllAction(), + new Separator()) + .addSecondarySearchActions(new ToggleInCommentsAction(), + new ToggleInLiteralsOnlyAction(), + new ToggleExceptCommentsAction(), + new ToggleExceptLiteralsAction(), + new ToggleExceptCommentsAndLiteralsAction()) + .addExtraSearchActions(new ToggleMatchCase(), + new ToggleRegex(), + new ToggleWholeWordsOnlyAction(), + new StatusTextAction(), + new DefaultCustomComponentAction(myClickToHighlightLabel)) + .addSearchFieldActions(new RestorePreviousSettingsAction()) + .addPrimaryReplaceActions(new ReplaceAction(), + new ReplaceAllAction(), + new ExcludeAction()) + .addExtraReplaceAction(new TogglePreserveCaseAction(), + new ToggleSelectionOnlyAction()) + .addReplaceFieldActions(createPrevOccurrenceAction(), + createNextOccurrenceAction()) + .withDataProvider(this) + .withCloseAction(new Runnable() { + @Override + public void run() { + close(); + } + }) + .withReplaceAction(new Runnable() { + @Override + public void run() { + replaceCurrent(); + } + }) + .withSecondarySearchActionsIsModifiedGetter(new BooleanGetter() { + @Override + public boolean get() { + return myFindModel.getSearchContext() != FindModel.SearchContext.ANY; + } + }) + .build(); + + myComponent.addListener(this); + new UiNotifyConnector(myComponent, new Activatable() { + @Override + public void showNotify() { + initLivePreview(); + } + + @Override + public void hideNotify() { + myLivePreviewController.off(); + mySearchResults.removeListener(EditorSearchSession.this); + } + }); + + new SwitchToFind(getComponent()); + new SwitchToReplace(getComponent()); + + myFindModel.addObserver(new FindModel.FindModelObserver() { + @Override + public void findModelChanged(FindModel findModel) { + String stringToFind = myFindModel.getStringToFind(); + if (!wholeWordsApplicable(stringToFind)) { + myFindModel.setWholeWordsOnly(false); + } + updateUIWithFindModel(); + updateResults(true); + syncFindModels(FindManager.getInstance(getProject()).getFindInFileModel(), myFindModel); + } + }); + + updateUIWithFindModel(); + + if (ApplicationManager.getApplication().isUnitTestMode()) { + initLivePreview(); + } + updateMultiLineStateIfNeed(); + } + + @Nullable + public static EditorSearchSession get(@Nullable Editor editor) { + JComponent headerComponent = editor != null ? editor.getHeaderComponent() : null; + SearchReplaceComponent searchReplaceComponent = ObjectUtils.tryCast(headerComponent, SearchReplaceComponent.class); + return searchReplaceComponent != null ? SESSION_KEY.getData(searchReplaceComponent) : null; + } + + @NotNull + public static EditorSearchSession start(@NotNull Editor editor, @Nullable Project project) { + EditorSearchSession session = new EditorSearchSession(editor, project); + editor.setHeaderComponent(session.getComponent()); + return session; + } + + @NotNull + public static EditorSearchSession start(@NotNull Editor editor, @NotNull FindModel findModel, @Nullable Project project) { + EditorSearchSession session = new EditorSearchSession(editor, project, findModel); + editor.setHeaderComponent(session.getComponent()); + return session; + } + + @NotNull + public SearchReplaceComponent getComponent() { + return myComponent; + } + + public Project getProject() { + return myComponent.getProject(); + } + + private static FindModel createDefaultFindModel(Project project, Editor editor) { + FindModel findModel = new FindModel(); + findModel.copyFrom(FindManager.getInstance(project).getFindInFileModel()); + if (editor.getSelectionModel().hasSelection()) { + String selectedText = editor.getSelectionModel().getSelectedText(); + if (selectedText != null) { + findModel.setStringToFind(selectedText); + } + } + findModel.setPromptOnReplace(false); + return findModel; + } + + + @Override + @Nullable + public Object getData(@NonNls final String dataId) { + if (SESSION_KEY.is(dataId)) { + return this; + } + if (CommonDataKeys.EDITOR_EVEN_IF_INACTIVE.is(dataId)) { + return myEditor; + } + return null; + } + + @Override + public void searchResultsUpdated(SearchResults sr) { + if (myComponent.getSearchTextComponent().getText().isEmpty()) { + updateUIWithEmptyResults(); + } else { + int matches = sr.getMatchesCount(); + boolean tooManyMatches = matches > mySearchResults.getMatchesLimit(); + myComponent.setStatusText(tooManyMatches + ? ApplicationBundle.message("editorsearch.toomuch", mySearchResults.getMatchesLimit()) + : ApplicationBundle.message("editorsearch.matches", matches)); + myClickToHighlightLabel.setVisible(tooManyMatches); + if (!tooManyMatches && matches <= 0) { + myComponent.setNotFoundBackground(); + } + else { + myComponent.setRegularBackground(); + } + } + myComponent.updateActions(); + } + + @Override + public void cursorMoved() { + myComponent.updateActions(); + } + + @Override + public void updateFinished() { + } + + @Override + public void searchFieldDocumentChanged() { + setMatchesLimit(LivePreviewController.MATCHES_LIMIT); + String text = myComponent.getSearchTextComponent().getText(); + myFindModel.setStringToFind(text); + if (!StringUtil.isEmpty(text)) { + updateResults(true); + } + else { + nothingToSearchFor(); + } + updateMultiLineStateIfNeed(); + } + + private void updateMultiLineStateIfNeed() { + myFindModel.setMultiline(myComponent.getSearchTextComponent().getText().contains("\n") || + myComponent.getReplaceTextComponent().getText().contains("\n")); + } + + @Override + public void replaceFieldDocumentChanged() { + setMatchesLimit(LivePreviewController.MATCHES_LIMIT); + myFindModel.setStringToReplace(myComponent.getReplaceTextComponent().getText()); + updateMultiLineStateIfNeed(); + } + + @Override + public void multilineStateChanged() { + myFindModel.setMultiline(myComponent.isMultiline()); + } + + public FindModel getFindModel() { + return myFindModel; + } + + private static void syncFindModels(FindModel to, FindModel from) { + to.setCaseSensitive(from.isCaseSensitive()); + to.setWholeWordsOnly(from.isWholeWordsOnly()); + to.setRegularExpressions(from.isRegularExpressions()); + to.setSearchContext(from.getSearchContext()); + if (from.isReplaceState()) { + to.setPreserveCase(from.isPreserveCase()); + } + } + + public void updateUIWithFindModel() { + myComponent.update(myFindModel.getStringToFind(), + myFindModel.getStringToReplace(), + myFindModel.isReplaceState(), + myFindModel.isMultiline()); + myLivePreviewController.setTrackingSelection(!myFindModel.isGlobal()); + } + + private static boolean wholeWordsApplicable(String stringToFind) { + return !stringToFind.startsWith(" ") && + !stringToFind.startsWith("\t") && + !stringToFind.endsWith(" ") && + !stringToFind.endsWith("\t"); + } + + private void setMatchesLimit(int value) { + mySearchResults.setMatchesLimit(value); + } + + private boolean canReplaceCurrent() { + return myLivePreviewController != null && myLivePreviewController.canReplace(); + } + + public void replaceCurrent() { + if (mySearchResults.getCursor() != null) { + myLivePreviewController.performReplace(); + } + } + + public void searchBackward() { + moveCursor(SearchResults.Direction.UP); + addTextToRecent(myComponent.getSearchTextComponent()); + } + + public void searchForward() { + moveCursor(SearchResults.Direction.DOWN); + addTextToRecent(myComponent.getSearchTextComponent()); + } + + public void addTextToRecent(JTextComponent textField) { + myComponent.addTextToRecent(textField); + } + + @Override + public void selectionChanged(SelectionEvent e) { + updateResults(false); + } + + private void moveCursor(SearchResults.Direction direction) { + myLivePreviewController.moveCursor(direction); + } + + public void close() { + IdeFocusManager.getInstance(getProject()).requestFocus(myEditor.getContentComponent(), false); + + myLivePreviewController.dispose(); + myEditor.setHeaderComponent(null); + } + + private void initLivePreview() { + myLivePreviewController.on(); + + myLivePreviewController.setUserActivityDelay(0); + updateResults(false); + myLivePreviewController.setUserActivityDelay(LivePreviewController.USER_ACTIVITY_TRIGGERING_DELAY); + + mySearchResults.addListener(this); + } + + private void updateResults(final boolean allowedToChangedEditorSelection) { + final String text = myFindModel.getStringToFind(); + if (text.length() == 0) { + nothingToSearchFor(); + } + else { + + if (myFindModel.isRegularExpressions()) { + try { + //noinspection ResultOfMethodCallIgnored + Pattern.compile(text); + } + catch (Exception e) { + myComponent.setNotFoundBackground(); + myClickToHighlightLabel.setVisible(false); + mySearchResults.clear(); + myComponent.setStatusText("Incorrect regular expression"); + return; + } + } + + + final FindManager findManager = FindManager.getInstance(getProject()); + if (allowedToChangedEditorSelection) { + findManager.setFindWasPerformed(); + FindModel copy = new FindModel(); + copy.copyFrom(myFindModel); + copy.setReplaceState(false); + findManager.setFindNextModel(copy); + } + if (myLivePreviewController != null) { + myLivePreviewController.updateInBackground(myFindModel, allowedToChangedEditorSelection); + } + } + } + + private void nothingToSearchFor() { + updateUIWithEmptyResults(); + if (mySearchResults != null) { + mySearchResults.clear(); + } + } + + private void updateUIWithEmptyResults() { + myComponent.setRegularBackground(); + myComponent.setStatusText(""); + myClickToHighlightLabel.setVisible(false); + } + + public String getTextInField() { + return myComponent.getSearchTextComponent().getText(); + } + + public void setTextInField(final String text) { + myComponent.getSearchTextComponent().setText(text); + myFindModel.setStringToFind(text); + } + + public boolean hasMatches() { + return mySearchResults != null && mySearchResults.hasMatches(); + } + + public void selectAllOccurrences() { + FindUtil.selectSearchResultsInEditor(myEditor, mySearchResults.getOccurrences().iterator(), -1); + } + + public void removeOccurrence() { + mySearchResults.prevOccurrence(true); + } + + public void addNextOccurrence() { + mySearchResults.nextOccurrence(true); + } + + public void clearUndoInTextFields() { + myComponent.resetUndoRedoActions(); + } + + + @NotNull + static NextOccurrenceAction createNextOccurrenceAction() { + return new NextOccurrenceAction(new PrevNextActionHandler() { + @Override + public void actionPerformed(AnActionEvent e) { + e.getRequiredData(SESSION_KEY).searchForward(); + } + }); + } + + @NotNull + static PrevOccurrenceAction createPrevOccurrenceAction() { + return new PrevOccurrenceAction(new PrevNextActionHandler() { + @Override + public void actionPerformed(AnActionEvent e) { + e.getRequiredData(SESSION_KEY).searchBackward(); + } + }); + } + + + private static abstract class ButtonAction extends DumbAwareAction implements CustomComponentAction, ActionListener { + private final String myTitle; + private final char myMnemonic; + + protected ButtonAction(@NotNull String title, char mnemonic) { + myTitle = title; + myMnemonic = mnemonic; + } + + @Override + public JComponent createCustomComponent(Presentation presentation) { + JButton button = new JButton(myTitle); + button.setFocusable(false); + if (!UISettings.getInstance().DISABLE_MNEMONICS_IN_CONTROLS) { + button.setMnemonic(myMnemonic); + } + button.addActionListener(this); + return button; + } + + @Override + public final void update(AnActionEvent e) { + JButton button = (JButton)e.getPresentation().getClientProperty(CUSTOM_COMPONENT_PROPERTY); + if (button != null) { + update(button); + } + } + + @Override + public final void actionPerformed(AnActionEvent e) { + onClick(); + } + + @Override + public final void actionPerformed(ActionEvent e) { + onClick(); + } + + protected abstract void update(@NotNull JButton button); + + protected abstract void onClick(); + } + + private class ReplaceAction extends ButtonAction { + public ReplaceAction() { + super("Replace", 'p'); + } + + @Override + protected void update(@NotNull JButton button) { + button.setEnabled(mySearchResults.hasMatches()); + } + + @Override + protected void onClick() { + replaceCurrent(); + } + } + + private class ReplaceAllAction extends ButtonAction { + public ReplaceAllAction() { + super("Replace all", 'a'); + } + + @Override + protected void update(@NotNull JButton button) { + button.setEnabled(mySearchResults.hasMatches()); + } + + @Override + protected void onClick() { + myLivePreviewController.performReplaceAll(); + } + } + + private class ExcludeAction extends ButtonAction { + public ExcludeAction() { + super("", 'l'); + } + + @Override + protected void update(@NotNull JButton button) { + FindResult cursor = mySearchResults.getCursor(); + button.setEnabled(cursor != null); + button.setText(cursor != null && mySearchResults.isExcluded(cursor) ? "Include" : "Exclude"); + } + + @Override + protected void onClick() { + myLivePreviewController.exclude(); + moveCursor(SearchResults.Direction.DOWN); + } + } + + private static abstract class PrevNextActionHandler implements PrevNextOccurrenceAction.Handler { + @Override + public void update(AnActionEvent e) { + EditorSearchSession search = e.getData(SESSION_KEY); + e.getPresentation().setEnabled(search != null && search.hasMatches()); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index fe1e9a24bff1..c70c98615c3e 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -192,10 +192,9 @@ public class FindUtil { model.setCaseSensitive(true); model.setWholeWordsOnly(!editor.getSelectionModel().hasSelection()); - final JComponent header = editor.getHeaderComponent(); - if (header instanceof EditorSearchComponent) { - final EditorSearchComponent searchComponent = (EditorSearchComponent)header; - searchComponent.setTextInField(model.getStringToFind()); + EditorSearchSession searchSession = EditorSearchSession.get(editor); + if (searchSession != null) { + searchSession.setTextInField(model.getStringToFind()); } findManager.setFindNextModel(model); diff --git a/platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java b/platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java new file mode 100644 index 000000000000..aa2ad6e3e504 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/SearchReplaceComponent.java @@ -0,0 +1,772 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.find; + +import com.intellij.find.editorHeaderActions.ContextAwareShortcutProvider; +import com.intellij.find.editorHeaderActions.ShowMoreOptions; +import com.intellij.find.editorHeaderActions.Utils; +import com.intellij.find.editorHeaderActions.VariantsCompletionAction; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.impl.EditorHeaderComponent; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.BooleanGetter; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.LightColors; +import com.intellij.ui.OnePixelSplitter; +import com.intellij.ui.SearchTextField; +import com.intellij.ui.components.panels.NonOpaquePanel; +import com.intellij.ui.components.panels.Wrapper; +import com.intellij.ui.speedSearch.SpeedSearchSupply; +import com.intellij.util.EventDispatcher; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.text.JTextComponent; +import java.awt.*; +import java.awt.event.*; +import java.util.Arrays; +import java.util.EventListener; +import java.util.List; + +public class SearchReplaceComponent extends EditorHeaderComponent implements DataProvider { + public static final DataKey COMPONENT_KEY = DataKey.create("search-replace-component"); + public static final DataKey STATUS_TEXT_KEY = DataKey.create("search-replace-status-text"); + + private final EventDispatcher myEventDispatcher = EventDispatcher.create(Listener.class); + + private final MyTextComponentWrapper mySearchFieldWrapper; + private JTextComponent mySearchTextComponent; + + private final MyTextComponentWrapper myReplaceFieldWrapper; + private JTextComponent myReplaceTextComponent; + + private final JPanel myLeftPanel; + private final JPanel myRightPanel; + + private final DefaultActionGroup mySearchFieldActions; + private final ActionToolbarImpl mySearchActionsToolbar1; + private final ActionToolbarImpl mySearchActionsToolbar2; + private final ActionToolbarImpl.PopupStateModifier mySearchToolbar1PopupStateModifier; + + private final DefaultActionGroup myReplaceFieldActions; + private final ActionToolbarImpl myReplaceActionsToolbar1; + private final ActionToolbarImpl myReplaceActionsToolbar2; + private final JPanel myReplaceToolbarWrapper; + + private final Project myProject; + private final JComponent myTargetComponent; + + private final Runnable myCloseAction; + private final Runnable myReplaceAction; + + private final DataProvider myDataProviderDelegate; + + private boolean myMultilineMode; + private String myStatusText; + + @NotNull + public static Builder buildFor(@Nullable Project project, @NotNull JComponent component) { + return new Builder(project, component); + } + + private SearchReplaceComponent(@Nullable Project project, + @NotNull JComponent targetComponent, + @NotNull DefaultActionGroup searchToolbar1Actions, + @NotNull final BooleanGetter searchToolbar1ModifiedFlagGetter, + @NotNull DefaultActionGroup searchToolbar2Actions, + @NotNull DefaultActionGroup searchFieldActions, + @NotNull DefaultActionGroup replaceToolbar1Actions, + @NotNull DefaultActionGroup replaceToolbar2Actions, + @NotNull DefaultActionGroup replaceFieldActions, + @Nullable Runnable replaceAction, + @Nullable Runnable closeAction, + @Nullable DataProvider dataProvider) { + myProject = project; + myTargetComponent = targetComponent; + mySearchFieldActions = searchFieldActions; + myReplaceFieldActions = replaceFieldActions; + myReplaceAction = replaceAction; + myCloseAction = closeAction; + + mySearchToolbar1PopupStateModifier = new ActionToolbarImpl.PopupStateModifier() { + @Override + public int getModifiedPopupState() { + return ActionButtonComponent.PUSHED; + } + + @Override + public boolean willModify() { + return searchToolbar1ModifiedFlagGetter.get(); + } + }; + + mySearchFieldWrapper = new MyTextComponentWrapper() { + @Override + public void setContent(JComponent wrapped) { + super.setContent(wrapped); + mySearchTextComponent = unwrapTextComponent(wrapped); + } + }; + myReplaceFieldWrapper = new MyTextComponentWrapper() { + @Override + public void setContent(JComponent wrapped) { + super.setContent(wrapped); + myReplaceTextComponent = unwrapTextComponent(wrapped); + } + }; + + myLeftPanel = new NonOpaquePanel(new BorderLayout()); + myLeftPanel.add(mySearchFieldWrapper, BorderLayout.NORTH); + myLeftPanel.add(myReplaceFieldWrapper, BorderLayout.CENTER); + + mySearchActionsToolbar1 = createSearchToolbar1(searchToolbar1Actions); + Wrapper searchToolbarWrapper1 = new NonOpaquePanel(new BorderLayout()); + searchToolbarWrapper1.add(mySearchActionsToolbar1, BorderLayout.WEST); + mySearchActionsToolbar2 = createSearchToolbar2(searchToolbar2Actions); + Wrapper searchToolbarWrapper2 = new Wrapper(mySearchActionsToolbar2); + mySearchActionsToolbar2.setBorder(JBUI.Borders.emptyLeft(16)); + JPanel searchPair = new NonOpaquePanel(new BorderLayout()).setVerticalSizeReferent(mySearchFieldWrapper); + searchPair.add(searchToolbarWrapper1, BorderLayout.WEST); + searchPair.add(searchToolbarWrapper2, BorderLayout.CENTER); + + myReplaceActionsToolbar1 = createReplaceToolbar1(replaceToolbar1Actions); + Wrapper replaceToolbarWrapper1 = new Wrapper(myReplaceActionsToolbar1).setVerticalSizeReferent(myReplaceFieldWrapper); + myReplaceActionsToolbar2 = createReplaceToolbar2(replaceToolbar2Actions); + Wrapper replaceToolbarWrapper2 = new Wrapper(myReplaceActionsToolbar2).setVerticalSizeReferent(myReplaceFieldWrapper); + myReplaceActionsToolbar2.setBorder(JBUI.Borders.emptyLeft(16)); + myReplaceToolbarWrapper = new NonOpaquePanel(new BorderLayout()); + myReplaceToolbarWrapper.add(replaceToolbarWrapper1, BorderLayout.WEST); + myReplaceToolbarWrapper.add(replaceToolbarWrapper2, BorderLayout.CENTER); + + searchToolbarWrapper1.setHorizontalSizeReferent(replaceToolbarWrapper1); + + JLabel closeLabel = new JLabel(null, AllIcons.Actions.Cross, SwingConstants.RIGHT); + closeLabel.setBorder(JBUI.Borders.empty(5)); + closeLabel.setVerticalAlignment(SwingConstants.TOP); + closeLabel.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(final MouseEvent e) { + close(); + } + }); + closeLabel.setToolTipText("Close search bar (Escape)"); + searchPair.add(new Wrapper.North(closeLabel), BorderLayout.EAST); + + myRightPanel = new NonOpaquePanel(new BorderLayout()); + myRightPanel.add(searchPair, BorderLayout.NORTH); + myRightPanel.add(myReplaceToolbarWrapper, BorderLayout.CENTER); + + OnePixelSplitter splitter = new OnePixelSplitter(false, .25F); + splitter.setFirstComponent(myLeftPanel); + splitter.setSecondComponent(myRightPanel); + splitter.setHonorComponentsMinimumSize(true); + splitter.setAndLoadSplitterProportionKey("FindSplitterProportion"); + splitter.setOpaque(false); + splitter.getDivider().setOpaque(false); + add(splitter, BorderLayout.CENTER); + + update("", "", false, false); + + // it's assigned after all action updates so that actions don't get access to uninitialized components + myDataProviderDelegate = dataProvider; + } + + public void resetUndoRedoActions() { + UIUtil.resetUndoRedoActions(mySearchTextComponent); + UIUtil.resetUndoRedoActions(myReplaceTextComponent); + } + + @Override + public void removeNotify() { + super.removeNotify(); + + addTextToRecent(mySearchTextComponent); + if (myReplaceTextComponent != null) { + addTextToRecent(myReplaceTextComponent); + } + } + + @Override + public void requestFocus() { + mySearchTextComponent.setSelectionStart(0); + mySearchTextComponent.setSelectionEnd(mySearchTextComponent.getText().length()); + IdeFocusManager.getInstance(myProject).requestFocus(mySearchTextComponent, true); + } + + public void setStatusText(@NotNull String status) { + myStatusText = status; + } + + public void replace() { + if (myReplaceAction != null) { + myReplaceAction.run(); + } + } + + public void close() { + if (myCloseAction != null ) { + myCloseAction.run(); + } + } + + public void setRegularBackground() { + mySearchTextComponent.setBackground(UIUtil.getTextFieldBackground()); + } + + public void setNotFoundBackground() { + mySearchTextComponent.setBackground(LightColors.RED); + } + + @Override + public Insets getInsets() { + Insets insets = super.getInsets(); + if (UIUtil.isUnderGTKLookAndFeel() || UIUtil.isUnderNimbusLookAndFeel()) { + insets.top += 1; + insets.bottom += 2; + } + return insets; + } + + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (STATUS_TEXT_KEY.is(dataId)) { + return myStatusText; + } + if (COMPONENT_KEY.is(dataId)) { + return this; + } + if (SpeedSearchSupply.SPEED_SEARCH_CURRENT_QUERY.is(dataId)) { + return mySearchTextComponent.getText(); + } + return myDataProviderDelegate != null ? myDataProviderDelegate.getData(dataId) : null; + } + + public Project getProject() { + return myProject; + } + + public void addListener(@NotNull Listener listener) { + myEventDispatcher.addListener(listener); + } + + public boolean isMultiline() { + return myMultilineMode; + } + + private void setMultilineInternal(boolean multiline) { + boolean stateChanged = multiline != myMultilineMode; + myMultilineMode = multiline; + if (stateChanged) { + multilineStateChanged(); + } + } + + @NotNull + public JTextComponent getSearchTextComponent() { + return mySearchTextComponent; + } + + @NotNull + public JTextComponent getReplaceTextComponent() { + return myReplaceTextComponent; + } + + + private void updateSearchComponent(@NotNull String textToSet) { + final int oldCaretPosition = mySearchTextComponent != null ? mySearchTextComponent.getCaretPosition() : 0; + boolean wasNull = mySearchTextComponent == null; + if (!updateTextComponent(true)) { + if (!mySearchTextComponent.getText().equals(textToSet)) { + mySearchTextComponent.setText(textToSet); + } + return; + } + + if (!mySearchTextComponent.getText().equals(textToSet)) { + mySearchTextComponent.setText(textToSet); + if (wasNull) { + mySearchTextComponent.selectAll(); + } + } + mySearchTextComponent.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + searchFieldDocumentChanged(); + } + }); + } + }); + + mySearchTextComponent.registerKeyboardAction(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + if (StringUtil.isEmpty(mySearchTextComponent.getText())) { + close(); + } + else { + IdeFocusManager.getInstance(myProject).requestFocus(myTargetComponent, true); + addTextToRecent(mySearchTextComponent); + } + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, SystemInfo.isMac ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK), + JComponent.WHEN_FOCUSED); + if (!wasNull) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + mySearchTextComponent.setCaretPosition(oldCaretPosition); + } + }); + } + + new VariantsCompletionAction(mySearchTextComponent); // It registers a shortcut set automatically on construction + } + + private void updateReplaceComponent(@NotNull String textToSet) { + final int oldCaretPosition = myReplaceTextComponent != null ? myReplaceTextComponent.getCaretPosition() : 0; + if (!updateTextComponent(false)) { + return; + } + myReplaceTextComponent.setText(textToSet); + + myReplaceTextComponent.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + replaceFieldDocumentChanged(); + } + }); + } + }); + + if (!isMultiline()) { + installReplaceOnEnterAction(myReplaceTextComponent); + } + + //myReplaceTextComponent.setText(myFindModel.getStringToReplace()); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + myReplaceTextComponent.setCaretPosition(oldCaretPosition); + } + }); + + new VariantsCompletionAction(myReplaceTextComponent); + myReplaceFieldWrapper.revalidate(); + myReplaceFieldWrapper.repaint(); + } + + public void update(@NotNull String findText, @NotNull String replaceText, boolean replaceMode, boolean multiline) { + setMultilineInternal(multiline); + boolean needToResetSearchFocus = mySearchTextComponent != null && mySearchTextComponent.hasFocus(); + boolean needToResetReplaceFocus = myReplaceTextComponent != null && myReplaceTextComponent.hasFocus(); + updateSearchComponent(findText); + updateReplaceComponent(replaceText); + if (replaceMode) { + if (myReplaceFieldWrapper.getParent() == null) { + myLeftPanel.add(myReplaceFieldWrapper, BorderLayout.CENTER); + } + if (myReplaceToolbarWrapper.getParent() == null) { + myRightPanel.add(myReplaceToolbarWrapper, BorderLayout.CENTER); + } + if (needToResetReplaceFocus) { + myReplaceTextComponent.requestFocusInWindow(); + } + } else { + if (myReplaceFieldWrapper.getParent() != null) { + myLeftPanel.remove(myReplaceFieldWrapper); + } + if (myReplaceToolbarWrapper.getParent() != null) { + myRightPanel.remove(myReplaceToolbarWrapper); + } + } + if (needToResetSearchFocus) mySearchTextComponent.requestFocusInWindow(); + updateBindings(); + updateActions(); + revalidate(); + repaint(); + } + + public void updateActions() { + mySearchActionsToolbar1.updateActionsImmediately(); + mySearchActionsToolbar2.updateActionsImmediately(); + myReplaceActionsToolbar1.updateActionsImmediately(); + myReplaceActionsToolbar2.updateActionsImmediately(); + } + + public void addTextToRecent(@NotNull JTextComponent textField) { + final String text = textField.getText(); + if (text.length() > 0) { + if (textField == mySearchTextComponent) { + FindSettings.getInstance().addStringToFind(text); + if (mySearchFieldWrapper.getTargetComponent() instanceof SearchTextField) { + ((SearchTextField)mySearchFieldWrapper.getTargetComponent()).addCurrentTextToHistory(); + } + } else { + FindSettings.getInstance().addStringToReplace(text); + if (myReplaceFieldWrapper.getTargetComponent() instanceof SearchTextField) { + ((SearchTextField)myReplaceFieldWrapper.getTargetComponent()).addCurrentTextToHistory(); + } + } + } + } + + private boolean updateTextComponent(boolean search) { + JTextComponent oldComponent = search ? mySearchTextComponent : myReplaceTextComponent; + Color oldBackground = oldComponent != null ? oldComponent.getBackground() : null; + final MyTextComponentWrapper wrapper = search ? mySearchFieldWrapper : myReplaceFieldWrapper; + if (isMultiline() && oldComponent instanceof JTextArea) return false; + if (!isMultiline() && oldComponent instanceof JTextField) return false; + + final JTextComponent textComponent; + if (isMultiline()) { + SearchTextArea textArea = new SearchTextArea(search); + textComponent = textArea.getTextArea(); + ((JTextArea)textComponent).setColumns(25); + ((JTextArea)textComponent).setRows(2); + wrapper.setContent(textArea); + } + else { + SearchTextField searchTextField = new SearchTextField(true); + searchTextField.setOpaque(false); + textComponent = searchTextField.getTextEditor(); + searchTextField.getTextEditor().setColumns(25); + if (UIUtil.isUnderGTKLookAndFeel()) { + textComponent.setOpaque(false); + } + searchTextField.setHistorySize(20); + searchTextField.setHistory(ContainerUtil.reverse(Arrays.asList(search ? FindSettings.getInstance().getRecentFindStrings() + : FindSettings.getInstance().getRecentReplaceStrings()))); + textComponent.registerKeyboardAction(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent e) { + final String text = textComponent.getText(); + setMultilineInternal(true); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ObjectUtils.assertNotNull(wrapper.getTextComponent()).setText(text + "\n"); + } + }); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.ALT_DOWN_MASK), JComponent.WHEN_FOCUSED); + wrapper.setContent(searchTextField); + } + + UIUtil.addUndoRedoActions(textComponent); + Utils.setSmallerFont(textComponent); + + textComponent.putClientProperty("AuxEditorComponent", Boolean.TRUE); + if (oldBackground != null) { + textComponent.setBackground(oldBackground); + } + textComponent.addFocusListener(new FocusListener() { + @Override + public void focusGained(final FocusEvent e) { + textComponent.repaint(); + } + + @Override + public void focusLost(final FocusEvent e) { + textComponent.repaint(); + } + }); + installCloseOnEscapeAction(textComponent); + return true; + } + + private void searchFieldDocumentChanged() { + if (mySearchTextComponent instanceof JTextArea) { + adjustRows((JTextArea)mySearchTextComponent); + } + myEventDispatcher.getMulticaster().searchFieldDocumentChanged(); + } + + private void replaceFieldDocumentChanged() { + if (myReplaceTextComponent instanceof JTextArea) { + adjustRows((JTextArea)myReplaceTextComponent); + } + myEventDispatcher.getMulticaster().replaceFieldDocumentChanged(); + } + + private void multilineStateChanged() { + myEventDispatcher.getMulticaster().multilineStateChanged(); + } + + private static void adjustRows(@NotNull JTextArea area) { + area.setRows(Math.max(2, Math.min(3, StringUtil.countChars(area.getText(),'\n')+1))); + } + + + private void installCloseOnEscapeAction(@NotNull JTextComponent c) { + ActionListener action = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + close(); + } + }; + c.registerKeyboardAction(action, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_FOCUSED); + if (KeymapUtil.isEmacsKeymap()) { + c.registerKeyboardAction(action, KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED); + } + } + + private void installReplaceOnEnterAction(@NotNull JTextComponent c) { + ActionListener action = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + replace(); + } + }; + c.registerKeyboardAction(action, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED); + } + + private void updateBindings() { + updateBindings(mySearchFieldActions, mySearchFieldWrapper); + updateBindings(mySearchActionsToolbar1, mySearchFieldWrapper); + updateBindings(mySearchActionsToolbar2, mySearchFieldWrapper); + + updateBindings(myReplaceFieldActions, myReplaceFieldWrapper); + updateBindings(myReplaceActionsToolbar1, myReplaceToolbarWrapper); + updateBindings(myReplaceActionsToolbar2, myReplaceToolbarWrapper); + } + + private void updateBindings(@NotNull DefaultActionGroup group, @NotNull JComponent shortcutHolder) { + updateBindings(ContainerUtil.immutableList(group.getChildActionsOrStubs()), shortcutHolder); + } + + private void updateBindings(@NotNull ActionToolbarImpl toolbar, @NotNull JComponent shortcutHolder) { + updateBindings(toolbar.getActions(true), shortcutHolder); + } + + private void updateBindings(@NotNull List actions, @NotNull JComponent shortcutHolder) { + DataContext context = DataManager.getInstance().getDataContext(this); + for (AnAction action : actions) { + ShortcutSet shortcut = null; + if (action instanceof ContextAwareShortcutProvider) { + shortcut = ((ContextAwareShortcutProvider)action).getShortcut(context); + } + else if (action instanceof ShortcutProvider) { + shortcut = ((ShortcutProvider)action).getShortcut(); + } + if (shortcut != null) { + action.registerCustomShortcutSet(shortcut, shortcutHolder); + } + } + } + + + @NotNull + private ActionToolbarImpl createSearchToolbar1(@NotNull DefaultActionGroup group) { + ActionToolbarImpl toolbar = createToolbar(group); + toolbar.setForceMinimumSize(true); + toolbar.setReservePlaceAutoPopupIcon(false); + toolbar.setSecondaryButtonPopupStateModifier(mySearchToolbar1PopupStateModifier); + toolbar.setSecondaryActionsTooltip("More Options(" + ShowMoreOptions.SHORT_CUT + ")"); + new ShowMoreOptions(toolbar, mySearchFieldWrapper); + return toolbar; + } + + @NotNull + private ActionToolbarImpl createSearchToolbar2(@NotNull DefaultActionGroup group) { + return createToolbar(group); + } + + @NotNull + private ActionToolbarImpl createReplaceToolbar1(@NotNull DefaultActionGroup group) { + ActionToolbarImpl toolbar = createToolbar(group); + toolbar.setForceMinimumSize(true); + toolbar.setReservePlaceAutoPopupIcon(false); + return toolbar; + } + + @NotNull + private ActionToolbarImpl createReplaceToolbar2(@NotNull DefaultActionGroup group) { + return createToolbar(group); + } + + @NotNull + private ActionToolbarImpl createToolbar(@NotNull ActionGroup group) { + return tweakToolbar((ActionToolbarImpl)ActionManager.getInstance().createActionToolbar(ActionPlaces.EDITOR_TOOLBAR, group, true)); + } + + @NotNull + private ActionToolbarImpl tweakToolbar(@NotNull ActionToolbarImpl toolbar) { + toolbar.setTargetComponent(this); + toolbar.setLayoutPolicy(ActionToolbar.AUTO_LAYOUT_POLICY); + toolbar.setBorder(null); + toolbar.setOpaque(false); + Utils.setSmallerFontForChildren(toolbar); + return toolbar; + } + + + public interface Listener extends EventListener { + void searchFieldDocumentChanged(); + + void replaceFieldDocumentChanged(); + + void multilineStateChanged(); + } + + public static class Builder { + private final Project myProject; + private final JComponent myTargetComponent; + + private DataProvider myDataProvider; + + private Runnable myReplaceAction; + private Runnable myCloseAction; + + private DefaultActionGroup mySearchActions = new DefaultActionGroup("search bar 1", false); + private DefaultActionGroup myExtraSearchActions = new DefaultActionGroup("search bar 2", false); + private DefaultActionGroup mySearchFieldActions = new DefaultActionGroup("search field actions", false); + private BooleanGetter mySearchToolbarModifiedFlagGetter = BooleanGetter.FALSE; + + private DefaultActionGroup myReplaceActions = new DefaultActionGroup("replace bar 1", false); + private DefaultActionGroup myExtraReplaceActions = new DefaultActionGroup("replace bar 1", false); + private DefaultActionGroup myReplaceFieldActions = new DefaultActionGroup("replace field actions", false); + + private Builder(@Nullable Project project, @NotNull JComponent component) { + myProject = project; + myTargetComponent = component; + } + + @NotNull + public Builder withDataProvider(@NotNull DataProvider provider) { + myDataProvider = provider; + return this; + } + + @NotNull + public Builder withReplaceAction(@NotNull Runnable action) { + myReplaceAction = action; + return this; + } + + @NotNull + public Builder withCloseAction(@NotNull Runnable action) { + myCloseAction = action; + return this; + } + + @NotNull + public Builder addSearchFieldActions(@NotNull AnAction... actions) { + mySearchFieldActions.addAll(actions); + return this; + } + + @NotNull + public Builder addReplaceFieldActions(@NotNull AnAction... actions) { + myReplaceFieldActions.addAll(actions); + return this; + } + + @NotNull + public Builder addPrimarySearchActions(@NotNull AnAction... actions) { + mySearchActions.addAll(actions); + return this; + } + + @NotNull + public Builder addSecondarySearchActions(@NotNull AnAction... actions) { + for (AnAction action : actions) { + mySearchActions.addAction(action).setAsSecondary(true); + } + return this; + } + + @NotNull + public Builder withSecondarySearchActionsIsModifiedGetter(@NotNull BooleanGetter getter) { + mySearchToolbarModifiedFlagGetter = getter; + return this; + } + + @NotNull + public Builder addExtraSearchActions(@NotNull AnAction... actions) { + myExtraSearchActions.addAll(actions); + return this; + } + + @NotNull + public Builder addPrimaryReplaceActions(@NotNull AnAction... actions) { + myReplaceActions.addAll(actions); + return this; + } + + @NotNull + public Builder addExtraReplaceAction(@NotNull AnAction... actions) { + myExtraReplaceActions.addAll(actions); + return this; + } + + @NotNull + public SearchReplaceComponent build() { + return new SearchReplaceComponent(myProject, + myTargetComponent, + mySearchActions, + mySearchToolbarModifiedFlagGetter, + myExtraSearchActions, + mySearchFieldActions, + myReplaceActions, + myExtraReplaceActions, + myReplaceFieldActions, + myReplaceAction, + myCloseAction, + myDataProvider); + } + } + + private static class MyTextComponentWrapper extends Wrapper { + @Nullable + public JTextComponent getTextComponent() { + JComponent wrapped = getTargetComponent(); + return wrapped != null ? unwrapTextComponent(wrapped) : null; + } + + @NotNull + protected static JTextComponent unwrapTextComponent(@NotNull JComponent wrapped) { + if (wrapped instanceof SearchTextField) { + return ((SearchTextField)wrapped).getTextEditor(); + } + if (wrapped instanceof SearchTextArea) { + return ((SearchTextArea)wrapped).getTextArea(); + } + throw new AssertionError(); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/find/SearchWrapper.java b/platform/lang-impl/src/com/intellij/find/SearchTextArea.java similarity index 54% rename from platform/lang-impl/src/com/intellij/find/SearchWrapper.java rename to platform/lang-impl/src/com/intellij/find/SearchTextArea.java index 3f37c3d0d9f7..bc1515d01056 100644 --- a/platform/lang-impl/src/com/intellij/find/SearchWrapper.java +++ b/platform/lang-impl/src/com/intellij/find/SearchTextArea.java @@ -15,37 +15,48 @@ */ package com.intellij.find; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.find.editorHeaderActions.Utils; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; +import com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI; import com.intellij.openapi.actionSystem.ActionPlaces; -import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.actionSystem.KeyboardShortcut; import com.intellij.openapi.actionSystem.impl.ActionButton; import com.intellij.openapi.actionSystem.impl.InplaceActionButtonLook; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.util.IconLoader; import com.intellij.ui.Gray; +import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.panels.NonOpaquePanel; +import com.intellij.util.ArrayUtil; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; import javax.swing.*; -import javax.swing.text.JTextComponent; import java.awt.*; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -class SearchWrapper extends NonOpaquePanel implements PropertyChangeListener, FocusListener { - private final JTextComponent myToWrap; +class SearchTextArea extends NonOpaquePanel implements PropertyChangeListener, FocusListener { + private final JTextArea myTextArea; - public SearchWrapper(JTextComponent toWrap, AnAction showHistoryAction) { - myToWrap = toWrap; + public SearchTextArea(boolean search) { + myTextArea = new JTextArea(); setBorder(JBUI.Borders.empty(6, 6, 6, 8)); setLayout(new BorderLayout(JBUI.scale(4), 0)); - myToWrap.addPropertyChangeListener("background", this); - myToWrap.addFocusListener(this); - myToWrap.setBorder(null); - myToWrap.setOpaque(false); - JBScrollPane scrollPane = new JBScrollPane(myToWrap, + myTextArea.addPropertyChangeListener("background", this); + myTextArea.addFocusListener(this); + myTextArea.setBorder(null); + myTextArea.setOpaque(false); + JBScrollPane scrollPane = new JBScrollPane(myTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.getVerticalScrollBar().setBackground(UIUtil.TRANSPARENT_COLOR); @@ -53,8 +64,9 @@ class SearchWrapper extends NonOpaquePanel implements PropertyChangeListener, Fo scrollPane.getViewport().setOpaque(false); scrollPane.setBorder(JBUI.Borders.emptyRight(2)); scrollPane.setOpaque(false); + ShowHistoryAction historyAction = new ShowHistoryAction(search); ActionButton button = - new ActionButton(showHistoryAction, showHistoryAction.getTemplatePresentation(), ActionPlaces.UNKNOWN, new Dimension(JBUI.scale(16), JBUI.scale(16))); + new ActionButton(historyAction, historyAction.getTemplatePresentation(), ActionPlaces.UNKNOWN, new Dimension(JBUI.scale(16), JBUI.scale(16))); button.setLook(new InplaceActionButtonLook()); JPanel p = new NonOpaquePanel(new BorderLayout()); p.add(button, BorderLayout.NORTH); @@ -62,6 +74,11 @@ class SearchWrapper extends NonOpaquePanel implements PropertyChangeListener, Fo add(scrollPane, BorderLayout.CENTER); } + @NotNull + public JTextArea getTextArea() { + return myTextArea; + } + @Override public Dimension getMinimumSize() { return getPreferredSize();//myToWrap.getPreferredScrollableViewportSize(); @@ -94,10 +111,10 @@ class SearchWrapper extends NonOpaquePanel implements PropertyChangeListener, Fo r.width -= JBUI.scale(9); r.height -= JBUI.scale(6); int arcSize = Math.min(25, r.height - 1) - 6; - g.setColor(myToWrap.getBackground()); - boolean hasFocus = myToWrap.hasFocus(); + g.setColor(myTextArea.getBackground()); + boolean hasFocus = myTextArea.hasFocus(); g.fillRoundRect(r.x, r.y + 1, r.width, r.height - 2, arcSize, arcSize); - g.setColor(myToWrap.isEnabled() ? Gray._100 : Gray._83); + g.setColor(myTextArea.isEnabled() ? Gray._100 : Gray._83); if (hasFocus) { DarculaUIUtil.paintSearchFocusRing(g, r, arcSize + 6); @@ -111,4 +128,29 @@ class SearchWrapper extends NonOpaquePanel implements PropertyChangeListener, Fo } super.paint(graphics); } + + private class ShowHistoryAction extends DumbAwareAction { + private final boolean myShowSearchHistory; + + public ShowHistoryAction(boolean search) { + super((search ? "Search" : "Replace") + " History", + (search ? "Search" : "Replace") + " history", + IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class, true)); + + myShowSearchHistory = search; + + KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.CTRL_DOWN_MASK); + registerCustomShortcutSet(new CustomShortcutSet(new KeyboardShortcut(stroke, null)), myTextArea); + } + + @Override + public void actionPerformed(AnActionEvent e) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("find.recent.search"); + String[] recent = myShowSearchHistory ? FindSettings.getInstance().getRecentFindStrings() + : FindSettings.getInstance().getRecentReplaceStrings(); + String title = "Recent " + (myShowSearchHistory ? "Searches" : "Replaces"); + JBList historyList = new JBList((Object[])ArrayUtil.reverseArray(recent)); + Utils.showCompletionPopup(myTextArea, historyList, title, myTextArea, null); + } + } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java index 813a549d0318..3ec0a8fc8a2f 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java @@ -15,32 +15,18 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.IdeActions; -import java.util.Arrays; - -public class AddOccurrenceAction extends EditorHeaderAction implements DumbAware { - public AddOccurrenceAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent); - - copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_NEXT_OCCURENCE)); - getTemplatePresentation().setIcon(AllIcons.Actions.AddMulticaret); - - registerShortcutsForComponent(Arrays.asList(getShortcutSet().getShortcuts()), editorSearchComponent.getSearchTextComponent()); +public class AddOccurrenceAction extends OccurrenceAction { + public AddOccurrenceAction() { + super(IdeActions.ACTION_SELECT_NEXT_OCCURENCE, AllIcons.Actions.AddMulticaret); } @Override public void actionPerformed(AnActionEvent e) { - myEditorSearchComponent.addNextOccurrence(); + e.getRequiredData(EditorSearchSession.SESSION_KEY).addNextOccurrence(); } - - @Override - public void update(AnActionEvent e) { - boolean isFind = !myEditorSearchComponent.getFindModel().isReplaceState(); - boolean hasMatches = myEditorSearchComponent.hasMatches(); - e.getPresentation().setVisible(isFind); - e.getPresentation().setEnabled(isFind && hasMatches); - }} +} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/CloseOnESCAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/CloseOnESCAction.java deleted file mode 100644 index 91837cb8acdb..000000000000 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/CloseOnESCAction.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.intellij.find.editorHeaderActions; - -import com.intellij.find.EditorSearchComponent; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.Shortcut; -import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.project.DumbAware; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; -import java.util.ArrayList; - -public class CloseOnESCAction extends EditorHeaderAction implements DumbAware { - public CloseOnESCAction(EditorSearchComponent editorSearchComponent, JComponent textField) { - super(editorSearchComponent); - - ArrayList shortcuts = new ArrayList(); - if (KeymapUtil.isEmacsKeymap()) { - shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_MASK), null)); - textField.registerKeyboardAction(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - CloseOnESCAction.this.actionPerformed(null); - } - }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_FOCUSED); - } else { - shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), null)); - } - - registerCustomShortcutSet(new CustomShortcutSet(shortcuts.toArray(new Shortcut[shortcuts.size()])), textField); - } - - @Override - public void actionPerformed(AnActionEvent e) { - myEditorSearchComponent.close(); - } -} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ContextAwareShortcutProvider.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ContextAwareShortcutProvider.java new file mode 100644 index 000000000000..9e35fd84abb1 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ContextAwareShortcutProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.ShortcutSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface ContextAwareShortcutProvider { + @Nullable + ShortcutSet getShortcut(@NotNull DataContext context); +} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java deleted file mode 100644 index 2e52b79bf659..000000000000 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.find.editorHeaderActions; - - -import com.intellij.find.EditorSearchComponent; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.actionSystem.Shortcut; - -import javax.swing.*; -import java.util.List; - -public abstract class EditorHeaderAction extends AnAction { - protected final EditorSearchComponent myEditorSearchComponent; - - protected EditorHeaderAction(EditorSearchComponent editorSearchComponent) { - myEditorSearchComponent = editorSearchComponent; - } - - protected void registerShortcutsForComponent(List shortcuts, JComponent component) { - registerCustomShortcutSet( - new CustomShortcutSet(shortcuts.toArray(new Shortcut[shortcuts.size()])), - component); - } -} - diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderSetSearchContextAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderSetSearchContextAction.java new file mode 100644 index 000000000000..e8f185a1ad93 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderSetSearchContextAction.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.find.EditorSearchSession; +import com.intellij.find.FindModel; +import org.jetbrains.annotations.NotNull; + +public class EditorHeaderSetSearchContextAction extends EditorHeaderToggleAction { + private final FindModel.SearchContext myContext; + + protected EditorHeaderSetSearchContextAction(@NotNull String text, @NotNull FindModel.SearchContext context) { + super(text); + + myContext = context; + } + + @Override + protected boolean isSelected(@NotNull EditorSearchSession session) { + return session.getFindModel().getSearchContext() == myContext; + } + + @Override + protected void setSelected(@NotNull EditorSearchSession session, boolean selected) { + session.getFindModel().setSearchContext(selected ? myContext : FindModel.SearchContext.ANY); + } +} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderToggleAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderToggleAction.java index d5cb872a1cee..aea1f7b9a968 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderToggleAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderToggleAction.java @@ -1,20 +1,17 @@ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ex.CheckboxAction; import com.intellij.openapi.project.DumbAware; +import org.jetbrains.annotations.NotNull; import javax.swing.*; public abstract class EditorHeaderToggleAction extends CheckboxAction implements DumbAware { - - protected final EditorSearchComponent myEditorSearchComponent; - - protected EditorHeaderToggleAction(EditorSearchComponent editorSearchComponent, String text) { + protected EditorHeaderToggleAction(@NotNull String text) { super(text); - myEditorSearchComponent = editorSearchComponent; } @Override @@ -34,4 +31,22 @@ public abstract class EditorHeaderToggleAction extends CheckboxAction implements customComponent.setOpaque(false); return customComponent; } + + @Override + public boolean isSelected(AnActionEvent e) { + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + return search != null && isSelected(search); + } + + @Override + public void setSelected(AnActionEvent e, boolean selected) { + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + if (search != null) { + setSelected(search, selected); + } + } + + protected abstract boolean isSelected(@NotNull EditorSearchSession session); + + protected abstract void setSelected(@NotNull EditorSearchSession session, boolean selected); } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/FindAllAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/FindAllAction.java index 08eefa018b24..dc0d4c11532d 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/FindAllAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/FindAllAction.java @@ -15,7 +15,7 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindManager; import com.intellij.find.FindModel; import com.intellij.find.FindUtil; @@ -29,6 +29,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.ui.LayeredIcon; import com.intellij.util.IconUtil; import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -39,45 +40,58 @@ import javax.swing.*; * Time: 10:53 * To change this template use File | Settings | File Templates. */ -public class FindAllAction extends EditorHeaderAction implements DumbAware { - public FindAllAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent); - Icon base = AllIcons.Actions.Find; - Icon text = IconUtil.textToIcon("ALL", editorSearchComponent, JBUI.scale(6F)); - LayeredIcon icon = new LayeredIcon(2); - icon.setIcon(base, 0); - icon.setIcon(text, 1, 0, base.getIconHeight() - text.getIconHeight()); - getTemplatePresentation().setIcon(icon); +public class FindAllAction extends AnAction implements ShortcutProvider, DumbAware { + public FindAllAction() { getTemplatePresentation().setDescription("Export matches to Find tool window"); getTemplatePresentation().setText("Find All"); - final AnAction findUsages = ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_USAGES); - if (findUsages != null) { - registerCustomShortcutSet(findUsages.getShortcutSet(), - editorSearchComponent.getSearchTextComponent()); - } } @Override public void update(final AnActionEvent e) { - Editor editor = e.getData(CommonDataKeys.EDITOR_EVEN_IF_INACTIVE); Project project = e.getProject(); - if (project != null && !project.isDisposed()) { - e.getPresentation().setEnabled(editor != null && myEditorSearchComponent.hasMatches() && - PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()) != null); - } + Editor editor = e.getData(CommonDataKeys.EDITOR_EVEN_IF_INACTIVE); + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + + updateTemplateIcon(search); + e.getPresentation().setIcon(getTemplatePresentation().getIcon()); + e.getPresentation().setEnabled(editor != null && project != null && search != null && + !project.isDisposed() && search.hasMatches() && + PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()) != null); } @Override public void actionPerformed(final AnActionEvent e) { - Editor editor = e.getData(CommonDataKeys.EDITOR_EVEN_IF_INACTIVE); - Project project = e.getProject(); - if (editor != null && project != null && !project.isDisposed()) { - final FindModel model = FindManager.getInstance(project).getFindInFileModel(); - final FindModel realModel = (FindModel)model.clone(); - String text = myEditorSearchComponent.getTextInField(); - if (StringUtil.isEmpty(text)) return; - realModel.setStringToFind(text); - FindUtil.findAllAndShow(project, editor, realModel); - } + Editor editor = e.getRequiredData(CommonDataKeys.EDITOR_EVEN_IF_INACTIVE); + Project project = e.getRequiredData(CommonDataKeys.PROJECT); + EditorSearchSession search = e.getRequiredData(EditorSearchSession.SESSION_KEY); + + if (project.isDisposed()) return; + + FindModel oldModel = FindManager.getInstance(project).getFindInFileModel(); + FindModel newModel = oldModel.clone(); + String text = search.getTextInField(); + if (StringUtil.isEmpty(text)) return; + + newModel.setStringToFind(text); + FindUtil.findAllAndShow(project, editor, newModel); + } + + @Nullable + @Override + public ShortcutSet getShortcut() { + AnAction findUsages = ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_USAGES); + return findUsages != null ? findUsages.getShortcutSet() : null; + } + + private void updateTemplateIcon(@Nullable EditorSearchSession session) { + if (session == null || getTemplatePresentation().getIcon() != null) return; + + Icon base = AllIcons.Actions.Find; + Icon text = IconUtil.textToIcon("ALL", session.getComponent(), JBUI.scale(6F)); + + LayeredIcon icon = new LayeredIcon(2); + icon.setIcon(base, 0); + icon.setIcon(text, 1, 0, base.getIconHeight() - text.getIconHeight()); + getTemplatePresentation().setIcon(icon); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java index 85eff5cc8155..3d393b71ac06 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -15,52 +15,28 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.actionSystem.CommonShortcuts; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; -import javax.swing.*; -import java.awt.event.KeyEvent; -import java.util.ArrayList; +import java.util.List; -/** -* Created by IntelliJ IDEA. -* User: zajac -* Date: 05.03.11 -* Time: 10:40 -* To change this template use File | Settings | File Templates. -*/ -public class NextOccurrenceAction extends EditorHeaderAction implements DumbAware { - private final boolean mySearch; - - public NextOccurrenceAction(EditorSearchComponent editorSearchComponent, JComponent shortcutHolder, boolean search) { - super(editorSearchComponent); - mySearch = search; - copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_NEXT_OCCURENCE)); - ArrayList shortcuts = new ArrayList(); - ContainerUtil.addAll(shortcuts, ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_NEXT).getShortcutSet().getShortcuts()); - if (!editorSearchComponent.getFindModel().isMultiline()) { - ContainerUtil - .addAll(shortcuts, ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN).getShortcutSet().getShortcuts()); - - shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), null)); - } - - registerShortcutsForComponent(shortcuts, shortcutHolder); +public final class NextOccurrenceAction extends PrevNextOccurrenceAction { + public NextOccurrenceAction(@NotNull Handler handler) { + super(IdeActions.ACTION_NEXT_OCCURENCE, handler); } + @NotNull @Override - public void actionPerformed(final AnActionEvent e) { - myEditorSearchComponent.searchForward(); + protected List getDefaultShortcuts() { + return Utils.shortcutsOf(IdeActions.ACTION_FIND_NEXT); } + @NotNull @Override - public void update(final AnActionEvent e) { - String textToSearch = mySearch - ? myEditorSearchComponent.getSearchTextComponent().getText() - : myEditorSearchComponent.getReplaceTextComponent().getText(); - e.getPresentation().setEnabled(myEditorSearchComponent.hasMatches() && !StringUtil.isEmpty(textToSearch)); + protected List getSingleLineShortcuts() { + return ContainerUtil.append(Utils.shortcutsOf(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN), CommonShortcuts.ENTER.getShortcuts()); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/OccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/OccurrenceAction.java new file mode 100644 index 000000000000..ed90d1f0b4db --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/OccurrenceAction.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.find.EditorSearchSession; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ShortcutProvider; +import com.intellij.openapi.actionSystem.ShortcutSet; +import com.intellij.openapi.project.DumbAwareAction; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public abstract class OccurrenceAction extends DumbAwareAction implements ShortcutProvider { + protected OccurrenceAction(@NotNull String baseActionId, @NotNull Icon icon) { + copyFrom(ActionManager.getInstance().getAction(baseActionId)); + getTemplatePresentation().setIcon(icon); + } + + @Override + public void update(AnActionEvent e) { + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + if (search == null) { + e.getPresentation().setEnabledAndVisible(false); + return; + } + + boolean isFind = !search.getFindModel().isReplaceState(); + boolean hasMatches = search.hasMatches(); + e.getPresentation().setVisible(isFind); + e.getPresentation().setEnabled(isFind && hasMatches); + } + + @Nullable + @Override + public ShortcutSet getShortcut() { + return getShortcutSet(); + } +} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevNextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevNextOccurrenceAction.java new file mode 100644 index 000000000000..0848c7ec728f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevNextOccurrenceAction.java @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.find.SearchReplaceComponent; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public abstract class PrevNextOccurrenceAction extends DumbAwareAction implements ContextAwareShortcutProvider { + private final Handler myHandler; + + PrevNextOccurrenceAction(@NotNull String templateActionId, @NotNull Handler handler) { + copyFrom(ActionManager.getInstance().getAction(templateActionId)); + myHandler = handler; + } + + @Override + public final void update(AnActionEvent e) { + myHandler.update(e); + } + + @Override + public final void actionPerformed(AnActionEvent e) { + myHandler.actionPerformed(e); + } + + @Nullable + @Override + public final ShortcutSet getShortcut(@NotNull DataContext context) { + SearchReplaceComponent searchComponent = SearchReplaceComponent.COMPONENT_KEY.getData(context); + boolean singleLine = searchComponent != null && !searchComponent.isMultiline(); + return Utils.shortcutSetOf(singleLine ? ContainerUtil.concat(getDefaultShortcuts(), getSingleLineShortcuts()) : getDefaultShortcuts()); + } + + @NotNull + protected abstract List getDefaultShortcuts(); + + @NotNull + protected abstract List getSingleLineShortcuts(); + + + public interface Handler { + void update(AnActionEvent e); + + void actionPerformed(AnActionEvent e); + } +} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java index 864221116ae6..69fdb153005a 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -15,48 +15,32 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.actionSystem.KeyboardShortcut; +import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import java.util.ArrayList; +import java.util.List; -/** -* Created by IntelliJ IDEA. -* User: zajac -* Date: 05.03.11 -* Time: 10:40 -* To change this template use File | Settings | File Templates. -*/ -public class PrevOccurrenceAction extends EditorHeaderAction implements DumbAware { - - public PrevOccurrenceAction(EditorSearchComponent editorSearchComponent, JComponent shortcutHolder) { - super(editorSearchComponent); - - copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_PREVIOUS_OCCURENCE)); - - ArrayList shortcuts = new ArrayList(); - ContainerUtil.addAll(shortcuts, ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_PREVIOUS).getShortcutSet().getShortcuts()); - if (!editorSearchComponent.getFindModel().isMultiline()) { - ContainerUtil.addAll(shortcuts, - ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_UP).getShortcutSet().getShortcuts()); - - shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK), null)); - } - registerShortcutsForComponent(shortcuts, shortcutHolder); +public final class PrevOccurrenceAction extends PrevNextOccurrenceAction { + public PrevOccurrenceAction(@NotNull Handler handler) { + super(IdeActions.ACTION_PREVIOUS_OCCURENCE, handler); } + @NotNull @Override - public void actionPerformed(final AnActionEvent e) { - myEditorSearchComponent.searchBackward(); + protected List getDefaultShortcuts() { + return Utils.shortcutsOf(IdeActions.ACTION_FIND_PREVIOUS); } + @NotNull @Override - public void update(final AnActionEvent e) { - e.getPresentation().setEnabled(myEditorSearchComponent.hasMatches()); + protected List getSingleLineShortcuts() { + return ContainerUtil.append(Utils.shortcutsOf(IdeActions.ACTION_EDITOR_MOVE_CARET_UP), + new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK), null)); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java index 7d4adb04825f..14877671748e 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java @@ -15,35 +15,18 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.project.DumbAware; -import java.util.Arrays; - -public class RemoveOccurrenceAction extends EditorHeaderAction implements DumbAware { - public RemoveOccurrenceAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent); - - copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE)); - getTemplatePresentation().setIcon(AllIcons.Actions.RemoveMulticaret); - - registerShortcutsForComponent(Arrays.asList(getShortcutSet().getShortcuts()), editorSearchComponent.getSearchTextComponent()); +public class RemoveOccurrenceAction extends OccurrenceAction { + public RemoveOccurrenceAction() { + super(IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE, AllIcons.Actions.RemoveMulticaret); } @Override public void actionPerformed(AnActionEvent e) { - myEditorSearchComponent.removeOccurrence(); - } - - @Override - public void update(AnActionEvent e) { - boolean isFind = !myEditorSearchComponent.getFindModel().isReplaceState(); - boolean hasMatches = myEditorSearchComponent.hasMatches(); - e.getPresentation().setVisible(isFind); - e.getPresentation().setEnabled(isFind && hasMatches); + e.getRequiredData(EditorSearchSession.SESSION_KEY).removeOccurrence(); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ReplaceOnEnterAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ReplaceOnEnterAction.java deleted file mode 100644 index 79dff47b8a9a..000000000000 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ReplaceOnEnterAction.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.intellij.find.editorHeaderActions; - -import com.intellij.find.EditorSearchComponent; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.actionSystem.KeyboardShortcut; -import com.intellij.openapi.actionSystem.Shortcut; - -import javax.swing.*; -import java.awt.event.KeyEvent; -import java.util.ArrayList; - -public class ReplaceOnEnterAction extends EditorHeaderAction { - public ReplaceOnEnterAction(EditorSearchComponent editorSearchComponent, JComponent shortcutHolder) { - super(editorSearchComponent); - ArrayList shortcuts = new ArrayList(); - shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), null)); - - registerCustomShortcutSet(new CustomShortcutSet(shortcuts.toArray(new Shortcut[shortcuts.size()])), shortcutHolder); - } - - @Override - public void actionPerformed(AnActionEvent e) { - myEditorSearchComponent.replaceCurrent(); - } -} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java index 31a4d0b1518b..d2b95b859030 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java @@ -15,16 +15,16 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindManager; import com.intellij.find.FindModel; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.KeyEvent; -import java.util.Collections; /** * Created by IntelliJ IDEA. @@ -33,33 +33,25 @@ import java.util.Collections; * Time: 10:40 * To change this template use File | Settings | File Templates. */ -public class RestorePreviousSettingsAction extends EditorHeaderAction implements DumbAware { - private final JComponent myShortcutHolder; - private static final KeyboardShortcut SHORTCUT = new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), null); - - public RestorePreviousSettingsAction(EditorSearchComponent editorSearchComponent, JComponent shortcutHolder) { - super(editorSearchComponent); - myShortcutHolder = shortcutHolder; - registerShortcutsForComponent(Collections.singletonList(SHORTCUT), shortcutHolder); +public class RestorePreviousSettingsAction extends AnAction implements ShortcutProvider, DumbAware { + @Override + public void update(AnActionEvent e) { + Project project = e.getProject(); + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + e.getPresentation().setEnabled(project != null && search != null && !project.isDisposed() && + search.getTextInField().isEmpty() && + FindManager.getInstance(project).getPreviousFindModel() != null); } @Override - public void actionPerformed(final AnActionEvent e) { - final FindModel model = FindManager.getInstance(e.getProject()).getPreviousFindModel(); - if (model != null) { - myEditorSearchComponent.getFindModel().copyFrom(model); - } + public void actionPerformed(AnActionEvent e) { + FindModel findModel = e.getRequiredData(EditorSearchSession.SESSION_KEY).getFindModel(); + findModel.copyFrom(FindManager.getInstance(e.getProject()).getPreviousFindModel()); } + @Nullable @Override - public void update(final AnActionEvent e) { - e.getPresentation().setEnabled( - e.getProject() != null - && myEditorSearchComponent.getSearchTextComponent().getText().isEmpty() - && FindManager.getInstance(e.getProject()).getPreviousFindModel() != null); - } - - public static String getAd() { - return "Use " + KeymapUtil.getShortcutText(SHORTCUT) + " to restore previous find/replace settings"; + public ShortcutSet getShortcut() { + return new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java index 0648e8222a36..9a0e6cef5d4e 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java @@ -15,39 +15,35 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAware; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; -public class SelectAllAction extends EditorHeaderAction implements DumbAware { - public SelectAllAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent); - - copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_ALL_OCCURRENCES)); - getTemplatePresentation().setIcon(AllIcons.Actions.CheckMulticaret); - - List shortcuts = new ArrayList(); - ContainerUtil.addAll(shortcuts, getShortcutSet().getShortcuts()); - ContainerUtil.addAll(shortcuts, CommonShortcuts.ALT_ENTER.getShortcuts()); - registerShortcutsForComponent(shortcuts, editorSearchComponent.getSearchTextComponent()); +public class SelectAllAction extends OccurrenceAction { + public SelectAllAction() { + super(IdeActions.ACTION_SELECT_ALL_OCCURRENCES, AllIcons.Actions.CheckMulticaret); } @Override public void actionPerformed(AnActionEvent e) { - myEditorSearchComponent.selectAllOccurrences(); - myEditorSearchComponent.close(); + EditorSearchSession search = e.getRequiredData(EditorSearchSession.SESSION_KEY); + search.selectAllOccurrences(); + search.close(); } + @Nullable @Override - public void update(AnActionEvent e) { - boolean isFind = !myEditorSearchComponent.getFindModel().isReplaceState(); - boolean hasMatches = myEditorSearchComponent.hasMatches(); - e.getPresentation().setVisible(isFind); - e.getPresentation().setEnabled(isFind && hasMatches); + public ShortcutSet getShortcut() { + List shortcuts = ContainerUtil.newArrayList(); + AnAction selectAllOccurrences = ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_ALL_OCCURRENCES); + if (selectAllOccurrences != null) { + ContainerUtil.addAll(shortcuts, selectAllOccurrences.getShortcutSet().getShortcuts()); + } + ContainerUtil.addAll(shortcuts, CommonShortcuts.ALT_ENTER.getShortcuts()); + return Utils.shortcutSetOf(shortcuts); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowHistoryAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowHistoryAction.java deleted file mode 100644 index bd27b7ac1163..000000000000 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowHistoryAction.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.intellij.find.editorHeaderActions; - -import com.intellij.find.EditorSearchComponent; -import com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.util.IconLoader; -import com.intellij.util.containers.ContainerUtil; - -import javax.swing.*; -import javax.swing.text.JTextComponent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; -import java.util.ArrayList; - -/** - * User: zajac - */ -public class ShowHistoryAction extends EditorHeaderAction implements DumbAware { - private final JTextComponent myTextField; - - public ShowHistoryAction(final JTextComponent textField, EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent); - myTextField = textField; - getTemplatePresentation().setIcon(IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class, true)); - final String s = myTextField == myEditorSearchComponent.getSearchTextComponent() ? "Search" : "Replace"; - getTemplatePresentation().setDescription(s + " history"); - getTemplatePresentation().setText(s + " History"); - - ArrayList shortcuts = new ArrayList(); - if (myTextField == myEditorSearchComponent.getSearchTextComponent()) { - //ContainerUtil.addAll(shortcuts, ActionManager.getInstance().getAction(IdeActions.ACTION_FIND).getShortcutSet().getShortcuts()); - ContainerUtil.addAll(shortcuts, ActionManager.getInstance().getAction("IncrementalSearch").getShortcutSet().getShortcuts()); - } - shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.CTRL_DOWN_MASK), null)); - - registerCustomShortcutSet(new CustomShortcutSet(shortcuts.toArray(new Shortcut[shortcuts.size()])), myTextField); - } - - @Override - public void update(AnActionEvent e) { - e.getPresentation().setVisible(myEditorSearchComponent.getFindModel().isMultiline()); - } - - @Override - public void actionPerformed(final AnActionEvent e) { - myEditorSearchComponent.showHistory(false, myTextField); - } -} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowMoreOptions.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowMoreOptions.java index a4ef20d88ea5..276b28448eda 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowMoreOptions.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ShowMoreOptions.java @@ -17,9 +17,10 @@ import java.awt.event.KeyEvent; * To change this template use File | Settings | File Templates. */ public class ShowMoreOptions extends AnAction implements DumbAware { - private final ActionToolbarImpl myToolbarComponent; public static final Shortcut SHORT_CUT = new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK), null); + private final ActionToolbarImpl myToolbarComponent; + public ShowMoreOptions(ActionToolbarImpl toolbarComponent, JComponent shortcutHolder) { this.myToolbarComponent = toolbarComponent; registerCustomShortcutSet(new CustomShortcutSet(SHORT_CUT), shortcutHolder); diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/StatusTextAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/StatusTextAction.java new file mode 100644 index 000000000000..0e0141c9384e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/StatusTextAction.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.find.editorHeaderActions; + +import com.intellij.find.SearchReplaceComponent; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ui.JBUI; + +import javax.swing.*; +import java.awt.*; + +public class StatusTextAction extends DumbAwareAction implements CustomComponentAction { + @Override + public void update(AnActionEvent e) { + String statusText = e.getData(SearchReplaceComponent.STATUS_TEXT_KEY); + JLabel label = (JLabel)e.getPresentation().getClientProperty(CUSTOM_COMPONENT_PROPERTY); + if (label != null) { + label.setText(StringUtil.notNullize(statusText)); + label.setVisible(StringUtil.isNotEmpty(statusText)); + } + } + + @Override + public void actionPerformed(AnActionEvent e) { + } + + @Override + public JComponent createCustomComponent(Presentation presentation) { + JLabel label = new JLabel() { + @Override + public Font getFont() { + Font font = super.getFont(); + return font != null ? font.deriveFont(Font.BOLD) : null; + } + }; + label.setBorder(JBUI.Borders.empty(2, 20, 0, 20)); + return label; + } +} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java index 74db01097118..673cf470f116 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java @@ -1,6 +1,6 @@ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindModel; import com.intellij.find.FindUtil; import com.intellij.openapi.actionSystem.ActionManager; @@ -9,6 +9,9 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAware; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; /** * Created by IntelliJ IDEA. @@ -17,12 +20,24 @@ import com.intellij.openapi.project.DumbAware; * Time: 10:57 * To change this template use File | Settings | File Templates. */ -public class SwitchToFind extends EditorHeaderAction implements DumbAware { - public SwitchToFind(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent); +public class SwitchToFind extends AnAction implements DumbAware { + public SwitchToFind(@NotNull JComponent shortcutHolder) { AnAction findAction = ActionManager.getInstance().getAction(IdeActions.ACTION_FIND); if (findAction != null) { - registerCustomShortcutSet(findAction.getShortcutSet(), editorSearchComponent); + registerCustomShortcutSet(findAction.getShortcutSet(), shortcutHolder); + } + } + + @Override + public void update(AnActionEvent e) { + if (KeymapUtil.isEmacsKeymap()) { + // Emacs users are accustomed to the editor that executes 'find next' on subsequent pressing of shortcut that + // activates 'incremental search'. Hence, we do the similar hack here for them. + ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_NEXT).update(e); + } + else { + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + e.getPresentation().setEnabledAndVisible(search != null); } } @@ -31,14 +46,13 @@ public class SwitchToFind extends EditorHeaderAction implements DumbAware { if (KeymapUtil.isEmacsKeymap()) { // Emacs users are accustomed to the editor that executes 'find next' on subsequent pressing of shortcut that // activates 'incremental search'. Hence, we do the similar hack here for them. - AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_NEXT); - action.update(e); - action.actionPerformed(e); + ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_NEXT).actionPerformed(e); return; } - final FindModel findModel = myEditorSearchComponent.getFindModel(); + EditorSearchSession search = e.getRequiredData(EditorSearchSession.SESSION_KEY); + final FindModel findModel = search.getFindModel(); FindUtil.configureFindModel(false, null, findModel, false); - myEditorSearchComponent.getSearchTextComponent().selectAll(); + search.getComponent().getSearchTextComponent().selectAll(); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java index 75b2eb782ac6..7ee08c600c7e 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java @@ -1,7 +1,7 @@ package com.intellij.find.editorHeaderActions; import com.intellij.execution.impl.ConsoleViewUtil; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindModel; import com.intellij.find.FindUtil; import com.intellij.openapi.actionSystem.ActionManager; @@ -9,6 +9,9 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.editor.Editor; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; /** * Created by IntelliJ IDEA. @@ -17,26 +20,26 @@ import com.intellij.openapi.editor.Editor; * Time: 10:57 * To change this template use File | Settings | File Templates. */ -public class SwitchToReplace extends EditorHeaderAction { - - public SwitchToReplace(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent); +public class SwitchToReplace extends AnAction { + public SwitchToReplace(@NotNull JComponent shortcutHolder) { AnAction replaceAction = ActionManager.getInstance().getAction("Replace"); if (replaceAction != null) { - registerCustomShortcutSet(replaceAction.getShortcutSet(), editorSearchComponent); + registerCustomShortcutSet(replaceAction.getShortcutSet(), shortcutHolder); } } @Override public void update(AnActionEvent e) { - final Editor editor = CommonDataKeys.EDITOR_EVEN_IF_INACTIVE.getData(e.getDataContext()); - e.getPresentation().setEnabled(editor != null && !ConsoleViewUtil.isConsoleViewEditor(editor)); + Editor editor = e.getData(CommonDataKeys.EDITOR_EVEN_IF_INACTIVE); + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + e.getPresentation().setEnabled(editor != null && search != null && !ConsoleViewUtil.isConsoleViewEditor(editor)); } @Override public void actionPerformed(AnActionEvent e) { - final FindModel findModel = myEditorSearchComponent.getFindModel(); + EditorSearchSession search = e.getRequiredData(EditorSearchSession.SESSION_KEY); + FindModel findModel = search.getFindModel(); FindUtil.configureFindModel(true, null, findModel, false); - myEditorSearchComponent.getSearchTextComponent().selectAll(); + search.getComponent().getSearchTextComponent().selectAll(); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAction.java index 8c4e329bc977..a3399f881219 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAction.java @@ -15,24 +15,10 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindModel; -import com.intellij.openapi.actionSystem.AnActionEvent; -public class ToggleExceptCommentsAction extends EditorHeaderToggleAction { - private static final String TEXT = "Except C&omments"; - - public ToggleExceptCommentsAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, TEXT); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isExceptComments(); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setSearchContext(state ? FindModel.SearchContext.EXCEPT_COMMENTS : FindModel.SearchContext.ANY); +public class ToggleExceptCommentsAction extends EditorHeaderSetSearchContextAction { + public ToggleExceptCommentsAction() { + super("Except C&omments", FindModel.SearchContext.EXCEPT_COMMENTS); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAndLiteralsAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAndLiteralsAction.java index 280bea317854..303ae8fa7d85 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAndLiteralsAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptCommentsAndLiteralsAction.java @@ -15,24 +15,10 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindModel; -import com.intellij.openapi.actionSystem.AnActionEvent; -public class ToggleExceptCommentsAndLiteralsAction extends EditorHeaderToggleAction { - private static final String TEXT = "Except Comments and Li&terals"; - - public ToggleExceptCommentsAndLiteralsAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, TEXT); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isExceptCommentsAndStringLiterals(); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setSearchContext(state ? FindModel.SearchContext.EXCEPT_COMMENTS_AND_STRING_LITERALS : FindModel.SearchContext.ANY); +public class ToggleExceptCommentsAndLiteralsAction extends EditorHeaderSetSearchContextAction { + public ToggleExceptCommentsAndLiteralsAction() { + super("Except Comments and Li&terals", FindModel.SearchContext.EXCEPT_COMMENTS_AND_STRING_LITERALS); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptLiteralsAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptLiteralsAction.java index 3ffcdd9a7c0c..97507f75ceaa 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptLiteralsAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleExceptLiteralsAction.java @@ -15,24 +15,10 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindModel; -import com.intellij.openapi.actionSystem.AnActionEvent; -public class ToggleExceptLiteralsAction extends EditorHeaderToggleAction { - private static final String TEXT = "Except L&iterals"; - - public ToggleExceptLiteralsAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, TEXT); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isExceptStringLiterals(); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setSearchContext(state ? FindModel.SearchContext.EXCEPT_STRING_LITERALS : FindModel.SearchContext.ANY); +public class ToggleExceptLiteralsAction extends EditorHeaderSetSearchContextAction { + public ToggleExceptLiteralsAction() { + super("Except L&iterals", FindModel.SearchContext.EXCEPT_STRING_LITERALS); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInCommentsAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInCommentsAction.java index 50bfd390daa1..378ec025fdc8 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInCommentsAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInCommentsAction.java @@ -1,23 +1,9 @@ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindModel; -import com.intellij.openapi.actionSystem.AnActionEvent; -public class ToggleInCommentsAction extends EditorHeaderToggleAction { - private static final String TEXT = "In &Comments Only"; - - public ToggleInCommentsAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, TEXT); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isInCommentsOnly(); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setSearchContext(state ? FindModel.SearchContext.IN_COMMENTS : FindModel.SearchContext.ANY); +public class ToggleInCommentsAction extends EditorHeaderSetSearchContextAction { + public ToggleInCommentsAction() { + super("In &Comments Only", FindModel.SearchContext.IN_COMMENTS); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInLiteralsOnlyAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInLiteralsOnlyAction.java index 2bfd30b2121e..07a542beedb3 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInLiteralsOnlyAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleInLiteralsOnlyAction.java @@ -1,23 +1,9 @@ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindModel; -import com.intellij.openapi.actionSystem.AnActionEvent; -public class ToggleInLiteralsOnlyAction extends EditorHeaderToggleAction { - private static final String TEXT = "In &Literals Only"; - - public ToggleInLiteralsOnlyAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, TEXT); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isInStringLiteralsOnly(); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setSearchContext(state ? FindModel.SearchContext.IN_STRING_LITERALS : FindModel.SearchContext.ANY); +public class ToggleInLiteralsOnlyAction extends EditorHeaderSetSearchContextAction { + public ToggleInLiteralsOnlyAction() { + super("In &Literals Only", FindModel.SearchContext.IN_STRING_LITERALS); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMatchCase.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMatchCase.java index 1c9d615f5130..62ef6a42803a 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMatchCase.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMatchCase.java @@ -15,25 +15,23 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindSettings; -import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; public class ToggleMatchCase extends EditorHeaderToggleAction { - private static final String CASE_SENSITIVE = "Match &Case"; - - public ToggleMatchCase(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, CASE_SENSITIVE); + public ToggleMatchCase() { + super("Match &Case"); } @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isCaseSensitive(); + protected boolean isSelected(@NotNull EditorSearchSession session) { + return session.getFindModel().isCaseSensitive(); } @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setCaseSensitive(state); - FindSettings.getInstance().setLocalCaseSensitive(state); + protected void setSelected(@NotNull EditorSearchSession session, boolean selected) { + session.getFindModel().setCaseSensitive(selected); + FindSettings.getInstance().setLocalCaseSensitive(selected); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMultiline.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMultiline.java deleted file mode 100644 index 44852cf6a7ca..000000000000 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleMultiline.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.intellij.find.editorHeaderActions; - -import com.intellij.find.EditorSearchComponent; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.ToggleAction; - - -public class ToggleMultiline extends ToggleAction { - private final EditorSearchComponent myEditorSearchComponent; - - public ToggleMultiline(EditorSearchComponent editorSearchComponent) { - super("Multiline", "Toggle Multiline Mode", AllIcons.Actions.ShowViewer); - myEditorSearchComponent = editorSearchComponent; - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isMultiline(); - } - - @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setMultiline(state); - } -} diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java index 28b47941f08e..60b4df84521b 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/TogglePreserveCaseAction.java @@ -15,31 +15,32 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindModel; import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; public class TogglePreserveCaseAction extends EditorHeaderToggleAction { - private static final String TEXT = "Pr&eserve Case"; - - public TogglePreserveCaseAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, TEXT); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isPreserveCase(); + public TogglePreserveCaseAction() { + super("Pr&eserve Case"); } @Override public void update(AnActionEvent e) { super.update(e); - FindModel findModel = myEditorSearchComponent.getFindModel(); - e.getPresentation().setEnabled(!findModel.isRegularExpressions()); + + EditorSearchSession search = e.getData(EditorSearchSession.SESSION_KEY); + FindModel findModel = search != null ? search.getFindModel() : null; + e.getPresentation().setEnabled(findModel != null && !findModel.isRegularExpressions()); } @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setPreserveCase(state); + protected boolean isSelected(@NotNull EditorSearchSession session) { + return session.getFindModel().isPreserveCase(); + } + + @Override + protected void setSelected(@NotNull EditorSearchSession session, boolean selected) { + session.getFindModel().setPreserveCase(selected); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java index fa8c8003a16e..adbfb1678173 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java @@ -15,31 +15,28 @@ */ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindModel; import com.intellij.find.FindSettings; -import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; public class ToggleRegex extends EditorHeaderToggleAction { - - private static final String REGEX = "Re&gex"; - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isRegularExpressions(); + public ToggleRegex() { + super("Re&gex"); } @Override - public void setSelected(AnActionEvent e, boolean state) { - final FindModel findModel = myEditorSearchComponent.getFindModel(); - findModel.setRegularExpressions(state); - if (state) { - findModel.setWholeWordsOnly(false); + protected boolean isSelected(@NotNull EditorSearchSession session) { + return session.getFindModel().isRegularExpressions(); + } + + @Override + protected void setSelected(@NotNull EditorSearchSession session, boolean selected) { + FindModel findModel = session.getFindModel(); + findModel.setRegularExpressions(selected); + if (selected) { + findModel.setWholeWordsOnly(true); } - FindSettings.getInstance().setLocalRegularExpressions(state); - } - - public ToggleRegex(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, REGEX); + FindSettings.getInstance().setLocalRegularExpressions(selected); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleSelectionOnlyAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleSelectionOnlyAction.java index 2b92daa25115..a07dca65159e 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleSelectionOnlyAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleSelectionOnlyAction.java @@ -1,30 +1,29 @@ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; public class ToggleSelectionOnlyAction extends EditorHeaderToggleAction { - private static final String SELECTION_ONLY = "In &Selection"; - - public ToggleSelectionOnlyAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, SELECTION_ONLY); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return !myEditorSearchComponent.getFindModel().isGlobal(); + public ToggleSelectionOnlyAction() { + super("In &Selection"); } @Override public void update(AnActionEvent e) { super.update(e); - final boolean replaceState = myEditorSearchComponent.getFindModel().isReplaceState(); - e.getPresentation().setVisible(replaceState); - e.getPresentation().setEnabled(replaceState); + + EditorSearchSession session = e.getData(EditorSearchSession.SESSION_KEY); + e.getPresentation().setEnabledAndVisible(session != null && session.getFindModel().isReplaceState()); } @Override - public void setSelected(AnActionEvent e, boolean state) { - myEditorSearchComponent.getFindModel().setGlobal(!state); + protected boolean isSelected(@NotNull EditorSearchSession session) { + return !session.getFindModel().isGlobal(); + } + + @Override + protected void setSelected(@NotNull EditorSearchSession session, boolean selected) { + session.getFindModel().setGlobal(!selected); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleWholeWordsOnlyAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleWholeWordsOnlyAction.java index e3a25c8332a7..266ec757a895 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleWholeWordsOnlyAction.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleWholeWordsOnlyAction.java @@ -1,31 +1,32 @@ package com.intellij.find.editorHeaderActions; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindSettings; import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; public class ToggleWholeWordsOnlyAction extends EditorHeaderToggleAction { - private static final String WHOLE_WORDS_ONLY = "Wo&rds"; - - public ToggleWholeWordsOnlyAction(EditorSearchComponent editorSearchComponent) { - super(editorSearchComponent, WHOLE_WORDS_ONLY); - } - - @Override - public boolean isSelected(AnActionEvent e) { - return myEditorSearchComponent.getFindModel().isWholeWordsOnly(); + public ToggleWholeWordsOnlyAction() { + super("Wo&rds"); } @Override public void update(AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(!myEditorSearchComponent.getFindModel().isRegularExpressions()); - e.getPresentation().setVisible(!myEditorSearchComponent.getFindModel().isMultiline()); + + EditorSearchSession session = e.getData(EditorSearchSession.SESSION_KEY); + e.getPresentation().setEnabled(session != null && !session.getFindModel().isRegularExpressions()); + e.getPresentation().setVisible(session != null && !session.getFindModel().isMultiline()); } @Override - public void setSelected(AnActionEvent e, boolean state) { - FindSettings.getInstance().setLocalWholeWordsOnly(state); - myEditorSearchComponent.getFindModel().setWholeWordsOnly(state); + protected boolean isSelected(@NotNull EditorSearchSession session) { + return session.getFindModel().isWholeWordsOnly(); + } + + @Override + protected void setSelected(@NotNull EditorSearchSession session, boolean selected) { + FindSettings.getInstance().setLocalWholeWordsOnly(selected); + session.getFindModel().setWholeWordsOnly(selected); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/Utils.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/Utils.java index cb03f56d512f..648b9d3a8e9e 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/Utils.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/Utils.java @@ -1,14 +1,21 @@ package com.intellij.find.editorHeaderActions; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupChooserBuilder; import com.intellij.openapi.util.SystemInfo; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.text.JTextComponent; import java.awt.*; +import java.util.List; public class Utils { private Utils() { @@ -62,4 +69,15 @@ public class Utils { } } } + + @NotNull + public static CustomShortcutSet shortcutSetOf(@NotNull List shortcuts) { + return new CustomShortcutSet(shortcuts.toArray(new Shortcut[shortcuts.size()])); + } + + @NotNull + public static List shortcutsOf(@NotNull String actionId) { + AnAction action = ActionManager.getInstance().getAction(actionId); + return action == null ? ContainerUtil.emptyList() : ContainerUtil.immutableList(action.getShortcutSet().getShortcuts()); + } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index bd2eb4973bd8..221d13bb9890 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -240,10 +240,9 @@ public class FindManagerImpl extends FindManager { public FindModel getFindNextModel(@NotNull final Editor editor) { if (myFindNextModel == null) return null; - final JComponent header = editor.getHeaderComponent(); - if (header instanceof EditorSearchComponent && !isSelectNextOccurrenceWasPerformed) { - final EditorSearchComponent searchComponent = (EditorSearchComponent)header; - final String textInField = searchComponent.getTextInField(); + EditorSearchSession search = EditorSearchSession.get(editor); + if (search != null && !isSelectNextOccurrenceWasPerformed) { + String textInField = search.getTextInField(); if (!Comparing.equal(textInField, myFindInFileModel.getStringToFind()) && !textInField.isEmpty()) { FindModel patched = new FindModel(); patched.copyFrom(myFindNextModel); @@ -930,16 +929,15 @@ public class FindManagerImpl extends FindManager { } private static boolean tryToFindNextUsageViaEditorSearchComponent(Editor editor, SearchResults.Direction forwardOrBackward) { - if (editor.getHeaderComponent() instanceof EditorSearchComponent) { - EditorSearchComponent searchComponent = (EditorSearchComponent)editor.getHeaderComponent(); - if (searchComponent.hasMatches()) { - if (forwardOrBackward == SearchResults.Direction.UP) { - searchComponent.searchBackward(); - } else { - searchComponent.searchForward(); - } - return true; + EditorSearchSession search = EditorSearchSession.get(editor); + if (search != null && search.hasMatches()) { + if (forwardOrBackward == SearchResults.Direction.UP) { + search.searchBackward(); } + else { + search.searchForward(); + } + return true; } return false; } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java index f6144b87d459..00346aeb29bd 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java @@ -42,7 +42,7 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep public static final int USER_ACTIVITY_TRIGGERING_DELAY = 30; public static final int MATCHES_LIMIT = 10000; - protected EditorSearchComponent myComponent; + protected EditorSearchSession myComponent; private int myUserActivityDelay = USER_ACTIVITY_TRIGGERING_DELAY; @@ -111,7 +111,7 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep return myReplaceDenied; } - public LivePreviewController(SearchResults searchResults, @Nullable EditorSearchComponent component) { + public LivePreviewController(SearchResults searchResults, @Nullable EditorSearchSession component) { mySearchResults = searchResults; myComponent = component; getEditor().getDocument().addDocumentListener(myDocumentListener); @@ -243,7 +243,7 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep mySuppressUpdate = false; } if (myComponent != null) { - myComponent.addTextToRecent(myComponent.getReplaceTextComponent()); + myComponent.addTextToRecent(myComponent.getComponent().getReplaceTextComponent()); myComponent.clearUndoInTextFields(); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java index f29bc30929aa..7ab37c2ebfe2 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java @@ -17,20 +17,18 @@ package com.intellij.openapi.editor.actions; import com.intellij.execution.impl.ConsoleViewUtil; -import com.intellij.find.EditorSearchComponent; +import com.intellij.find.EditorSearchSession; import com.intellij.find.FindManager; import com.intellij.find.FindModel; import com.intellij.find.FindUtil; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.project.Project; - -import javax.swing.*; +import com.intellij.openapi.wm.IdeFocusManager; public class IncrementalFindAction extends EditorAction { public static class Handler extends EditorActionHandler { @@ -46,11 +44,10 @@ public class IncrementalFindAction extends EditorAction { public void execute(final Editor editor, DataContext dataContext) { final Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(editor.getComponent())); if (!editor.isOneLineMode()) { - final JComponent headerComponent = editor.getHeaderComponent(); - if (headerComponent instanceof EditorSearchComponent) { - EditorSearchComponent editorSearchComponent = (EditorSearchComponent)headerComponent; - headerComponent.requestFocus(); - FindUtil.configureFindModel(myReplace, editor, editorSearchComponent.getFindModel(), false); + EditorSearchSession search = EditorSearchSession.get(editor); + if (search != null) { + IdeFocusManager.getInstance(project).requestFocus(search.getComponent(), true); + FindUtil.configureFindModel(myReplace, editor, search.getFindModel(), false); } else { FindManager findManager = FindManager.getInstance(project); FindModel model; @@ -61,9 +58,7 @@ public class IncrementalFindAction extends EditorAction { model.copyFrom(findManager.getFindInFileModel()); } FindUtil.configureFindModel(myReplace, editor, model, true); - final EditorSearchComponent header = new EditorSearchComponent(editor, project, model); - editor.setHeaderComponent(header); - header.requestFocus(); + EditorSearchSession.start(editor, model, project).getComponent().requestFocus(); } } } diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java index ae2a4dc0d53c..d0ff3ff00784 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java @@ -16,8 +16,6 @@ package com.intellij.openapi.editor.actions; import com.intellij.find.*; -import com.intellij.find.editorHeaderActions.EditorHeaderAction; -import com.intellij.find.editorHeaderActions.SelectAllAction; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java index 74390f15b149..7e4ed84e19b3 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java @@ -16,8 +16,6 @@ package com.intellij.openapi.editor.actions; import com.intellij.find.*; -import com.intellij.find.editorHeaderActions.AddOccurrenceAction; -import com.intellij.find.editorHeaderActions.EditorHeaderAction; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor; diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java index 1858ef53b3f5..7dd9d392ae66 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java @@ -19,10 +19,8 @@ import com.intellij.codeInsight.editorActions.SelectWordUtil; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.codeInsight.hint.HintUtil; -import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindBundle; import com.intellij.find.FindModel; -import com.intellij.find.editorHeaderActions.EditorHeaderAction; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.Editor;