From 8dac8f0155edf647a3845612d34305eb8dc1fac3 Mon Sep 17 00:00:00 2001 From: andrey zaytsev Date: Fri, 25 Feb 2011 21:20:37 +0300 Subject: [PATCH] IDEA-65866, IDEA-65752: refactoring of interaction between header component and model. --- .../src/com/intellij/find/FindManager.java | 3 + .../src/com/intellij/find/FindModel.java | 132 ++++++++ .../highlighting/HighlightUsagesHandler.java | 2 + .../intellij/find/EditorSearchComponent.java | 286 +++++++++++------- .../intellij/find/impl/FindManagerImpl.java | 9 + .../editor/actions/IncrementalFindAction.java | 40 ++- 6 files changed, 351 insertions(+), 121 deletions(-) diff --git a/platform/lang-api/src/com/intellij/find/FindManager.java b/platform/lang-api/src/com/intellij/find/FindManager.java index c2866ebe6d94..1a3b01687e67 100644 --- a/platform/lang-api/src/com/intellij/find/FindManager.java +++ b/platform/lang-api/src/com/intellij/find/FindManager.java @@ -31,6 +31,9 @@ import org.jetbrains.annotations.Nullable; public abstract class FindManager { public static final Topic FIND_MODEL_TOPIC = new Topic("FindManager's model changes", FindModelListener.class); + + public abstract FindModel createReplaceInFileModel(); + /** * Returns the find manager instance for the specified project. * diff --git a/platform/lang-api/src/com/intellij/find/FindModel.java b/platform/lang-api/src/com/intellij/find/FindModel.java index 88f946e98fa2..ea140fe0ca8b 100644 --- a/platform/lang-api/src/com/intellij/find/FindModel.java +++ b/platform/lang-api/src/com/intellij/find/FindModel.java @@ -17,11 +17,13 @@ package com.intellij.find; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.search.SearchScope; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -32,6 +34,26 @@ import java.util.regex.PatternSyntaxException; public class FindModel extends UserDataHolderBase implements Cloneable { private static final Logger LOG = Logger.getInstance("#com.intellij.find.FindModel"); + public interface FindModelObserver { + void findModelChanged(FindModel findModel); + } + + private CopyOnWriteArrayList myObservers = new CopyOnWriteArrayList(); + + public void addObserver(FindModelObserver observer) { + myObservers.add(observer); + } + + public void removeObserver(FindModelObserver observer) { + myObservers.remove(observer); + } + + private void notifyObservers() { + for (FindModelObserver observer : myObservers) { + observer.findModelChanged(this); + } + } + private String myStringToFind = ""; private String myStringToReplace = ""; private boolean isSearchHighlighters = false; @@ -134,8 +156,12 @@ public class FindModel extends UserDataHolderBase implements Cloneable { */ public void setStringToFind(@NotNull String s) { LOG.assertTrue(s.length() > 0); + boolean changed = !StringUtil.equals(s, myStringToFind); myStringToFind = s; myPattern = NO_PATTERN; + if (changed) { + notifyObservers(); + } } /** @@ -154,7 +180,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param s the string to replace with. */ public void setStringToReplace(@NotNull String s) { + boolean changed = !StringUtil.equals(s, myStringToReplace); myStringToReplace = s; + if (changed) { + notifyObservers(); + } } /** @@ -172,7 +202,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param val true if the operation is a Replace, false if it is a Find. */ public void setReplaceState(boolean val) { + boolean changed = val != isReplaceState; isReplaceState = val; + if (changed) { + notifyObservers(); + } } /** @@ -190,7 +224,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param val true if the origin is From Cursor, false if it is Entire Scope. */ public void setFromCursor(boolean val) { + boolean changed = val != isFromCursor; isFromCursor = val; + if (changed) { + notifyObservers(); + } } /** @@ -208,7 +246,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param val true if the find is forward, false if it is backward. */ public void setForward(boolean val) { + boolean changed = val != isForward; isForward = val; + if (changed) { + notifyObservers(); + } } /** @@ -226,7 +268,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param val the value of the Regular Expressions flag. */ public void setRegularExpressions(boolean val) { + boolean changed = val != isRegularExpressions; isRegularExpressions = val; + if (changed) { + notifyObservers(); + } } /** @@ -244,7 +290,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param val the value of the Case Sensitive flag. */ public void setCaseSensitive(boolean val) { + boolean changed = val != isCaseSensitive; isCaseSensitive = val; + if (changed) { + notifyObservers(); + } } /** @@ -262,7 +312,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param val true if the operation affects multiple files, false if it affects a single file. */ public void setMultipleFiles(boolean val) { + boolean changed = val != isMultipleFiles; isMultipleFiles = val; + if (changed) { + notifyObservers(); + } } /** @@ -280,7 +334,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param val the value of the Prompt on Replace flag. */ public void setPromptOnReplace(boolean val) { + boolean changed = val != isPromptOnReplace; isPromptOnReplace = val; + if (changed) { + notifyObservers(); + } } /** @@ -298,7 +356,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param isWholeWordsOnly the value of the Whole Words Only flag. */ public void setWholeWordsOnly(boolean isWholeWordsOnly) { + boolean changed = isWholeWordsOnly != this.isWholeWordsOnly; this.isWholeWordsOnly = isWholeWordsOnly; + if (changed) { + notifyObservers(); + } } /** @@ -316,7 +378,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param isGlobal true if the operation affects the entire file, false if it affects the selected text. */ public void setGlobal(boolean isGlobal) { + boolean changed = this.isGlobal != isGlobal; this.isGlobal = isGlobal; + if (changed) { + notifyObservers(); + } } /** @@ -334,7 +400,9 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param replaceAll the value of the Replace All flag. */ public void setReplaceAll(boolean replaceAll) { + boolean changed = isReplaceAll != replaceAll; isReplaceAll = replaceAll; + notifyObservers(); } /** @@ -352,7 +420,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param showInNewTab the value of the Open in New Tab flag. */ public void setOpenInNewTab(boolean showInNewTab) { + boolean changed = showInNewTab != isOpenNewTab; isOpenNewTab = showInNewTab; + if (changed) { + notifyObservers(); + } } /** @@ -370,7 +442,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param showInNewTabEnabled true if Open in New Tab is enabled, false otherwise. */ public void setOpenInNewTabEnabled(boolean showInNewTabEnabled) { + boolean changed = isOpenInNewTabEnabled != showInNewTabEnabled; isOpenInNewTabEnabled = showInNewTabEnabled; + if (changed) { + notifyObservers(); + } } /** @@ -388,7 +464,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param showInNewTabVisible true if Open in New Tab is visible, false otherwise. */ public void setOpenInNewTabVisible(boolean showInNewTabVisible) { + boolean changed = showInNewTabVisible != isOpenNewTabVisible; isOpenNewTabVisible = showInNewTabVisible; + if (changed) { + notifyObservers(); + } } /** @@ -407,7 +487,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param directoryName the directory scope. */ public void setDirectoryName(String directoryName) { + boolean changed = !StringUtil.equals(directoryName, directoryName); this.directoryName = directoryName; + if (changed) { + notifyObservers(); + } } /** @@ -425,7 +509,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param withSubdirectories true if directories are searched recursively, false otherwise. */ public void setWithSubdirectories(boolean withSubdirectories) { + boolean changed = withSubdirectories != isWithSubdirectories; isWithSubdirectories = withSubdirectories; + if (changed) { + notifyObservers(); + } } /** @@ -445,7 +533,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param projectScope true if the whole project scope is selected, false otherwise. */ public void setProjectScope(boolean projectScope) { + boolean changed = projectScope != isProjectScope; isProjectScope = projectScope; + if (changed) { + notifyObservers(); + } } public Object clone() { @@ -499,7 +591,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param search true if the operation moves between highlighted regions, false otherwise. */ public void setSearchHighlighters(boolean search) { + boolean changed = search != isSearchHighlighters; isSearchHighlighters = search; + if (changed) { + notifyObservers(); + } } /** @@ -517,7 +613,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param fileFilter the file name filter text. */ public void setFileFilter(String fileFilter) { + boolean changed = !StringUtil.equals(fileFilter, this.fileFilter); this.fileFilter = fileFilter; + if (changed) { + notifyObservers(); + } } /** @@ -538,7 +638,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param moduleName the name of the module used as the scope. */ public void setModuleName(String moduleName) { + boolean changed = !StringUtil.equals(moduleName, this.moduleName); this.moduleName = moduleName; + if (changed) { + notifyObservers(); + } } /** @@ -560,7 +664,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @since 5.1 */ public void setFindAll(final boolean findAll) { + boolean changed = isFindAll != findAll; isFindAll = findAll; + if (changed) { + notifyObservers(); + } } /** @@ -580,7 +688,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @since 5.1 */ public void setFindAllEnabled(final boolean findAllEnabled) { + boolean changed = isFindAllEnabled != findAllEnabled; isFindAllEnabled = findAllEnabled; + if (changed) { + notifyObservers(); + } } public String getCustomScopeName() { @@ -588,7 +700,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { } public void setCustomScopeName(String customScopeName) { + boolean changed = !StringUtil.equals(customScopeName, this.customScopeName); this.customScopeName = customScopeName; + if (changed) { + notifyObservers(); + } } public SearchScope getCustomScope() { @@ -596,7 +712,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { } public void setCustomScope(final SearchScope customScope) { + boolean changed = this.customScope.equals(customScope); this.customScope = customScope; + if (changed) { + notifyObservers(); + } } public boolean isCustomScope() { @@ -604,7 +724,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { } public void setCustomScope(boolean customScope) { + boolean changed = isCustomScope != customScope; isCustomScope = customScope; + if (changed) { + notifyObservers(); + } } public boolean isInStringLiteralsOnly() { @@ -612,7 +736,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { } public void setInStringLiteralsOnly(boolean inStringLiteralsOnly) { + boolean changed = isInStringLiteralsOnly != inStringLiteralsOnly; isInStringLiteralsOnly = inStringLiteralsOnly; + if (changed) { + notifyObservers(); + } } public boolean isInCommentsOnly() { @@ -620,7 +748,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { } public void setInCommentsOnly(boolean inCommentsOnly) { + boolean changed = isInCommentsOnly != inCommentsOnly; isInCommentsOnly = inCommentsOnly; + if (changed) { + notifyObservers(); + } } private static final Pattern NO_PATTERN = Pattern.compile(""); 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 a551c29d48fe..b1f71dc4a593 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandler.java @@ -19,6 +19,8 @@ package com.intellij.codeInsight.highlighting; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.TargetElementUtilBase; import com.intellij.find.EditorSearchComponent; +import com.intellij.find.FindManager; +import com.intellij.find.FindModel; import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.injection.InjectedLanguageManager; diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index 8a38ca076080..9c617f762af2 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -29,6 +29,8 @@ import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.actions.IncrementalFindAction; +import com.intellij.openapi.editor.actions.ReplaceAction; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.SelectionEvent; import com.intellij.openapi.editor.event.SelectionListener; @@ -37,7 +39,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.psi.PsiDocumentManager; @@ -67,7 +68,8 @@ import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; -public class EditorSearchComponent extends JPanel implements DataProvider, SelectionListener, SearchResults.SearchResultsListener { +public class EditorSearchComponent extends JPanel implements DataProvider, SelectionListener, SearchResults.SearchResultsListener, + FindModel.FindModelObserver { private static final int MATCHES_LIMIT = 10000; private final JLabel myMatchInfoLabel; private final LinkLabel myClickToHighlightLabel; @@ -104,11 +106,24 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec private final LivePreview myLivePreview; - private boolean myIsReplace; private boolean myListeningSelection = false; private SearchResults mySearchResults; private Balloon myOptionsBalloon; + private final FindModel myFindModel; + private JCheckBox myCbMatchCase; + private JPanel myReplacementPane; + + private static FindModel createDefaultFindModel(Project p) { + FindModel findModel = new FindModel(); + findModel.copyFrom(FindManager.getInstance(p).getFindInFileModel()); + return findModel; + } + + public EditorSearchComponent(Editor editor, Project project) { + this(editor, project, createDefaultFindModel(project)); + } + @Nullable public Object getData(@NonNls final String dataId) { if (PlatformDataKeys.EDITOR_EVEN_IF_INACTIVE.is(dataId)) { @@ -117,10 +132,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec return null; } - public EditorSearchComponent(final Editor e, Project p) { - this(e, p, false); - } - @Override public void searchResultsUpdated(SearchResults sr) { int count = sr.getActualFound(); @@ -163,11 +174,9 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec @Override public void editorChanged(SearchResults sr, Editor oldEditor) { } - public EditorSearchComponent(final Editor editor, final Project project, boolean isReplace) { + public EditorSearchComponent(final Editor editor, final Project project, FindModel findModel) { super(new BorderLayout(0, 0)); - - myIsReplace = isReplace; - + myFindModel = findModel; GRADIENT_C1 = getBackground(); GRADIENT_C2 = new Color(Math.max(0, GRADIENT_C1.getRed() - 0x18), Math.max(0, GRADIENT_C1.getGreen() - 0x18), Math.max(0, GRADIENT_C1.getBlue() - 0x18)); @@ -199,6 +208,8 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec group.add(new PrevOccurrenceAction()); group.add(new NextOccurrenceAction()); group.add(new FindAllAction()); + group.add(new IncrementalFindAction()); + group.add(new ReplaceAction()); final ActionToolbar tb = ActionManager.getInstance().createActionToolbar("SearchBar", group, true); tb.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY); @@ -207,7 +218,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myToolbarComponent.setOpaque(false); leadPanel.add(myToolbarComponent); - final JCheckBox cbMatchCase = new NonFocusableCheckBox("Case sensitive"); + myCbMatchCase = new NonFocusableCheckBox("Case sensitive"); myCbWholeWords = new NonFocusableCheckBox("Match whole words only"); myCbRegexp = new NonFocusableCheckBox("Regex"); myCbInComments = new NonFocusableCheckBox("Search in comments only"); @@ -216,7 +227,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myOptionsPane = new JPanel(); myOptionsPane.setLayout(new BoxLayout(myOptionsPane, BoxLayout.Y_AXIS)); - leadPanel.add(cbMatchCase); + leadPanel.add(myCbMatchCase); myOptionsPane.add(myCbWholeWords); leadPanel.add(myCbRegexp); if (FindManagerImpl.ourHasSearchInCommentsAndLiterals) { @@ -238,38 +249,40 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } }); + leadPanel.add(myMoreOptionsButton); - cbMatchCase.setSelected(isCaseSensitive()); - myCbWholeWords.setSelected(isWholeWords()); - myCbRegexp.setSelected(isRegexp()); - myCbInComments.setSelected(isInComments()); - myCbInLiterals.setSelected(isInLiterals()); + myFindModel.addObserver(new FindModel.FindModelObserver() { + @Override + public void findModelChanged(FindModel findModel) { + syncFindModels(FindManager.getInstance(myProject).getFindInFileModel(), myFindModel); + updateUIWithFindModel(); + updateResults(true); + } + }); - cbMatchCase.setMnemonic('C'); + FindManager.getInstance(myProject).getFindInFileModel().addObserver(this); + + updateUIWithFindModel(); + + myCbMatchCase.setMnemonic('C'); myCbWholeWords.setMnemonic('M'); myCbRegexp.setMnemonic('x'); myCbInComments.setMnemonic('o'); myCbInLiterals.setMnemonic('l'); setSmallerFontAndOpaque(myCbWholeWords); - setSmallerFontAndOpaque(cbMatchCase); + setSmallerFontAndOpaque(myCbMatchCase); setSmallerFontAndOpaque(myCbRegexp); setSmallerFontAndOpaque(myCbInComments); setSmallerFontAndOpaque(myCbInLiterals); - if (myIsReplace) { - configureReplacementPane(); - myReplaceField.putClientProperty("AuxEditorComponent", Boolean.TRUE); - } - - cbMatchCase.addActionListener(new ActionListener() { + myCbMatchCase.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { - final boolean b = cbMatchCase.isSelected(); + final boolean b = myCbMatchCase.isSelected(); FindManager.getInstance(myProject).getFindInFileModel().setCaseSensitive(b); FindSettings.getInstance().setLocalCaseSensitive(b); - updateResults(true); } }); @@ -278,7 +291,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec final boolean b = myCbWholeWords.isSelected(); FindManager.getInstance(myProject).getFindInFileModel().setWholeWordsOnly(b); FindSettings.getInstance().setLocalWholeWordsOnly(b); - updateResults(true); } }); @@ -286,11 +298,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec public void actionPerformed(final ActionEvent e) { final boolean b = myCbRegexp.isSelected(); FindManager.getInstance(myProject).getFindInFileModel().setRegularExpressions(b); - myCbWholeWords.setEnabled(!b); - if (myPreserveCase != null) { - myPreserveCase.setEnabled(!b); - } - updateResults(true); } }); @@ -298,7 +305,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec public void actionPerformed(final ActionEvent e) { final boolean b = myCbInComments.isSelected(); FindManager.getInstance(myProject).getFindInFileModel().setInCommentsOnly(b); - updateResults(true); } }); @@ -306,7 +312,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec public void actionPerformed(final ActionEvent e) { final boolean b = myCbInLiterals.isSelected(); FindManager.getInstance(myProject).getFindInFileModel().setInStringLiteralsOnly(b); - updateResults(true); } }); @@ -345,6 +350,17 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec tailPanel.add(closeLabel, BorderLayout.EAST); configureTextField(mySearchField); + mySearchField.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + setMatchesLimit(MATCHES_LIMIT); + String text = mySearchField.getText(); + if (!StringUtil.isEmpty(text)) { + myFindModel.setStringToFind(text); + updateResults(true); + } + } + }); + setSmallerFont(mySearchField); mySearchField.registerKeyboardAction(new ActionListener() { public void actionPerformed(final ActionEvent e) { @@ -359,7 +375,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, SystemInfo.isMac ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_FOCUSED); - final String initialText = myEditor.getSelectionModel().getSelectedText(); + final String initialText = myFindModel.getStringToFind(); ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { @@ -368,8 +384,87 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec }); new VariantsCompletionAction(); // It registers a shortcut set automatically on construction + } + @Override + public void findModelChanged(FindModel findModel) { + syncFindModels(myFindModel, findModel); + } + public boolean isRegexp() { + return myFindModel.isRegularExpressions(); + } + + public void setRegexp(boolean val) { + myFindModel.setRegularExpressions(val); + } + + 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.setInCommentsOnly(from.isInCommentsOnly()); + to.setInStringLiteralsOnly(from.isInStringLiteralsOnly()); + } + + private void updateFindModelWithUI() { + myFindModel.setCaseSensitive(myCbMatchCase.isSelected()); + myFindModel.setWholeWordsOnly(myCbWholeWords.isSelected()); + myFindModel.setRegularExpressions(myCbRegexp.isSelected()); + myFindModel.setInCommentsOnly(myCbInComments.isSelected()); + myFindModel.setInStringLiteralsOnly(myCbInLiterals.isSelected()); + myFindModel.setFromCursor(false); + myFindModel.setSearchHighlighters(true); + + } + + private void updateUIWithFindModel() { + myCbMatchCase.setSelected(myFindModel.isCaseSensitive()); + myCbWholeWords.setSelected(myFindModel.isWholeWordsOnly()); + myCbWholeWords.setEnabled(!myFindModel.isRegularExpressions()); + myCbRegexp.setSelected(myFindModel.isRegularExpressions()); + myCbInComments.setSelected(myFindModel.isInCommentsOnly()); + myCbInLiterals.setSelected(myFindModel.isInStringLiteralsOnly()); + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + String stringToFind = myFindModel.getStringToFind(); + boolean changed = StringUtil.equals(stringToFind, mySearchField.getText()); + mySearchField.setText(stringToFind); + if (changed) { + updateResults(true); + } + } + }); + + setTrackingSelection(!myFindModel.isGlobal()); + + if (myFindModel.isReplaceState() && myReplacementPane == null) { + configureReplacementPane(); + } else if (!myFindModel.isReplaceState() && myReplacementPane != null) { + remove(myReplacementPane); + myReplacementPane = null; + } + if (myFindModel.isReplaceState()) { + mySelectionOnly.setSelected(!myFindModel.isGlobal()); + myPreserveCase.setSelected(myFindModel.isPreserveCase()); + myPreserveCase.setEnabled(!myFindModel.isRegularExpressions()); + myPreserveCase.setEnabled(!myFindModel.isWholeWordsOnly()); + updateExcludeStatus(); + } + + } + + private static FindModel createFindModel(FindModel findInFileModel, boolean isReplace) { + FindModel result = new FindModel(); + result.copyFrom(findInFileModel); + if (isReplace) { + result.setReplaceState(isReplace); + } + return result; } private void setMatchesLimit(int value) { @@ -377,43 +472,44 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } private void configureReplacementPane() { - JPanel replacement = createLeadPane(); + myReplacementPane = createLeadPane(); myReplaceField = createTextField(); configureTextField(myReplaceField); + myReplaceField.getDocument().addDocumentListener(new DocumentAdapter() { + protected void textChanged(final DocumentEvent e) { + setMatchesLimit(MATCHES_LIMIT); + myFindModel.setStringToReplace(myReplaceField.getText()); + } + }); myReplaceField.registerKeyboardAction(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { myLivePreviewController.performReplace(); } }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED); - replacement.add(myReplaceField); - add(replacement, BorderLayout.SOUTH); + myReplaceField.setText(myFindModel.getStringToReplace()); + myReplacementPane.add(myReplaceField); + add(myReplacementPane, BorderLayout.SOUTH); myPreserveCase = new JCheckBox("Preserve case"); mySelectionOnly = new JCheckBox("Selection only"); - final FindModel findInFileModel = FindManager.getInstance(myProject).getFindInFileModel(); myPreserveCase.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { final boolean b = myPreserveCase.isSelected(); - findInFileModel.setPreserveCase(b); - updateResults(true); + myFindModel.setPreserveCase(b); } }); myPreserveCase.setMnemonic('P'); mySelectionOnly.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { - updateModelWithSelectionMode(findInFileModel); - updateResults(true); + final boolean b = mySelectionOnly.isSelected(); + myFindModel.setGlobal(!b); } }); mySelectionOnly.setMnemonic('S'); - updateModelWithSelectionMode(findInFileModel); - mySelectionOnly.setSelected(!findInFileModel.isGlobal()); - myPreserveCase.setSelected(findInFileModel.isPreserveCase()); - myPreserveCase.setEnabled(!findInFileModel.isRegularExpressions()); myReplaceButton = new JButton("Replace"); myReplaceButton.addActionListener(new ActionListener() { @@ -434,7 +530,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myReplaceAllButton.setMnemonic('a'); myExcludeButton = new JButton(""); - updateExcludeStatus(); + myExcludeButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { @@ -443,9 +539,9 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec }); myExcludeButton.setMnemonic('l'); - replacement.add(myReplaceButton); - replacement.add(myReplaceAllButton); - replacement.add(myExcludeButton); + myReplacementPane.add(myReplaceButton); + myReplacementPane.add(myReplaceAllButton); + myReplacementPane.add(myExcludeButton); myOptionsPane.add(mySelectionOnly); myOptionsPane.add(myPreserveCase); @@ -457,6 +553,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec setSmallerFontAndOpaque(mySelectionOnly); setSmallerFontAndOpaque(myPreserveCase); setSmallerFont(myReplaceField); + myReplaceField.putClientProperty("AuxEditorComponent", Boolean.TRUE); } private void updateExcludeStatus() { @@ -474,11 +571,16 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } } - private void updateModelWithSelectionMode(FindModel findInFileModel) { + private void updateModelWithSelectionMode() { final boolean b = mySelectionOnly.isSelected(); - findInFileModel.setGlobal(!b); + myFindModel.setGlobal(!b); + } + + private void setTrackingSelection(boolean b) { if (b) { - myEditor.getSelectionModel().addSelectionListener(this); + if (!myListeningSelection) { + myEditor.getSelectionModel().addSelectionListener(this); + } } else { if (myListeningSelection) { myEditor.getSelectionModel().removeSelectionListener(this); @@ -518,12 +620,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } }); - searchField.getDocument().addDocumentListener(new DocumentAdapter() { - protected void textChanged(final DocumentEvent e) { - setMatchesLimit(MATCHES_LIMIT); - updateResults(true); - } - }); + searchField.registerKeyboardAction(new ActionListener() { public void actionPerformed(final ActionEvent e) { @@ -544,7 +641,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec public void setInitialText(final String initialText) { final String text = initialText != null ? initialText : ""; if (text.contains("\n")) { - setRegexp(true); + myFindModel.setRegularExpressions(true); setTextInField(StringUtil.escapeToRegexp(text)); } else { @@ -613,6 +710,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myEditor.getSelectionModel().removeSelection(); } IdeFocusManager.getInstance(myProject).requestFocus(myEditor.getContentComponent(), false); + FindManager.getInstance(myProject).getFindInFileModel().removeObserver(this); mySearchResults.dispose(); myLivePreview.cleanUp(); myEditor.setHeaderComponent(null); @@ -656,14 +754,9 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec nothingToSearchFor(); } else { - final FindModel model = new FindModel(); - model.setCaseSensitive(isCaseSensitive()); - model.setInCommentsOnly(isInComments()); - model.setInStringLiteralsOnly(isInLiterals()); + setRegularBackground(); - if (isRegexp()) { - model.setWholeWordsOnly(false); - model.setRegularExpressions(true); + if (myFindModel.isRegularExpressions()) { try { Pattern.compile(text); } @@ -675,31 +768,18 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec return; } } - else { - model.setWholeWordsOnly(isWholeWords()); - model.setRegularExpressions(false); - } - model.setFromCursor(false); - model.setStringToFind(text); - model.setSearchHighlighters(true); final FindManager findManager = FindManager.getInstance(myProject); if (allowedToChangedEditorSelection) { findManager.setFindWasPerformed(); FindModel copy = new FindModel(); - copy.copyFrom(model); + copy.copyFrom(myFindModel); + copy.setReplaceState(false); findManager.setFindNextModel(copy); } - if (myIsReplace) { - model.setReplaceState(true); - model.setStringToReplace(myReplaceField.getText()); - model.setPromptOnReplace(false); - model.setGlobal(!mySelectionOnly.isSelected()); - model.setPreserveCase(myPreserveCase.isEnabled() && myPreserveCase.isSelected()); - } - myLivePreviewController.updateInBackground(model, allowedToChangedEditorSelection); + myLivePreviewController.updateInBackground(myFindModel, allowedToChangedEditorSelection); } } @@ -728,35 +808,11 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec return mySearchField.getText(); } - private boolean isWholeWords() { - return FindManager.getInstance(myProject).getFindInFileModel().isWholeWordsOnly(); - } - - private boolean isInComments() { - return FindManager.getInstance(myProject).getFindInFileModel().isInCommentsOnly(); - } - - private boolean isInLiterals() { - return FindManager.getInstance(myProject).getFindInFileModel().isInStringLiteralsOnly(); - } - - private boolean isCaseSensitive() { - return FindManager.getInstance(myProject).getFindInFileModel().isCaseSensitive(); - } - - public boolean isRegexp() { - return myCbRegexp.isSelected() || FindManager.getInstance(myProject).getFindInFileModel().isRegularExpressions(); - } - - public void setRegexp(boolean r) { - myCbRegexp.setSelected(r); - myCbWholeWords.setEnabled(!r); - updateResults(false); - } - public void setTextInField(final String text) { mySearchField.setText(text); - updateResults(true); + if (!StringUtil.isEmpty(text)) { + myFindModel.setStringToFind(text); + } } private class PrevOccurrenceAction extends AnAction implements DumbAware { @@ -770,7 +826,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK), null)); registerShortcutsForComponent(shortcuts, mySearchField, this); - if (myIsReplace) { + if (myFindModel.isReplaceState()) { registerShortcutsForComponent(shortcuts, myReplaceField, this); } } @@ -804,7 +860,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), null)); registerShortcutsForComponent(shortcuts, mySearchField, this); - if (myIsReplace) { + if (myFindModel.isReplaceState()) { registerShortcutsForComponent(shortcuts, myReplaceField, this); } } 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 9f3c590b9a91..6de8050d843b 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -114,6 +114,15 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo myFindInProjectModel.setMultipleFiles(true); } + @Override + public FindModel createReplaceInFileModel() { + FindModel model = new FindModel(); + model.copyFrom(getFindInFileModel()); + model.setReplaceState(true); + model.setPromptOnReplace(false); + return model; + } + public Element getState() { Element element = new Element("FindManager"); final Element findUsages = new Element(FIND_USAGES_MANAGER_ELEMENT); 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 2f2535ff5e9f..f4c5f3f6d814 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,6 +17,8 @@ package com.intellij.openapi.editor.actions; import com.intellij.find.EditorSearchComponent; +import com.intellij.find.FindManager; +import com.intellij.find.FindModel; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -24,6 +26,7 @@ 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 com.intellij.openapi.util.text.StringUtil; import javax.swing.*; @@ -41,18 +44,43 @@ public class IncrementalFindAction extends EditorAction { final Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(editor.getComponent())); if (!editor.isOneLineMode()) { final JComponent headerComponent = editor.getHeaderComponent(); + String selectedText = editor.getSelectionModel().getSelectedText(); if (headerComponent instanceof EditorSearchComponent) { - if (myReplace) { - ((EditorSearchComponent)headerComponent).replaceCurrent(); - } else { - ((EditorSearchComponent) headerComponent).setInitialText(editor.getSelectionModel().getSelectedText()); + EditorSearchComponent editorSearchComponent = (EditorSearchComponent)headerComponent; + if (!myReplace) { + editorSearchComponent.setInitialText(selectedText); headerComponent.requestFocus(); } + if (myReplace != editorSearchComponent.getFindModel().isReplaceState()){ + editorSearchComponent.getFindModel().setReplaceState(myReplace); + } } else { - final EditorSearchComponent header = new EditorSearchComponent(editor, project, myReplace); + FindManager findManager = FindManager.getInstance(project); + FindModel model = null; + if (myReplace) { + model = findManager.createReplaceInFileModel(); + if (!StringUtil.isEmpty(selectedText)) { + if (selectedText.indexOf('\n') >= 0) { + model.setGlobal(false); + } + else { + model.setStringToFind(selectedText); + model.setGlobal(true); + } + } + else { + model.setGlobal(true); + } + } else { + model = new FindModel(); + model.copyFrom(findManager.getFindInFileModel()); + } + if (selectedText != null && model.isGlobal()) { + model.setStringToFind(selectedText); + } + final EditorSearchComponent header = new EditorSearchComponent(editor, project, model); editor.setHeaderComponent(header); - header.requestFocus(); } }