replace in project works with new usage view, find in path has 'skip with one usage' is with subdirectories is saved / restored across find calls

This commit is contained in:
Maxim Mossienko
2005-03-02 15:15:25 +03:00
parent 3d681344f6
commit 8146eb81ec
11 changed files with 423 additions and 380 deletions
@@ -109,18 +109,22 @@ public class UsageInfo2UsageAdapter implements Usage, UsageInModule, UsageInLibr
public void selectInEditor() {
if (!isValid()) return;
Editor editor = openTextEditor(false);
RangeMarker marker = myRangeMarkers.get(0);
RangeMarker marker = getRangeMarker();
editor.getSelectionModel().setSelection(marker.getStartOffset(), marker.getEndOffset());
}
public void highlightInEditor() {
if (!isValid()) return;
RangeMarker marker = myRangeMarkers.get(0);
RangeMarker marker = getRangeMarker();
SelectInEditorManager.getInstance(getProject())
.selectInEditor(getFile(), marker.getStartOffset(), marker.getEndOffset(), false, false);
}
public final RangeMarker getRangeMarker() {
return myRangeMarkers.get(0);
}
public void navigate(boolean focus) {
if (canNavigate()) {
openTextEditor(focus);
@@ -141,7 +145,7 @@ public class UsageInfo2UsageAdapter implements Usage, UsageInModule, UsageInLibr
}
private OpenFileDescriptor getDescriptor() {
return isValid() ? new OpenFileDescriptor(getProject(), getFile(), myRangeMarkers.get(0).getStartOffset()) : null;
return isValid() ? new OpenFileDescriptor(getProject(), getFile(), getRangeMarker().getStartOffset()) : null;
}
private Project getProject() {
@@ -217,7 +221,7 @@ public class UsageInfo2UsageAdapter implements Usage, UsageInModule, UsageInLibr
public void reset() {
if (myRangeMarkers.size() > 1) {
RangeMarker marker = myRangeMarkers.get(0);
RangeMarker marker = getRangeMarker();
myRangeMarkers = new ArrayList<RangeMarker>();
myRangeMarkers.add(marker);
initChunks();
@@ -25,8 +25,10 @@ public interface UsageView extends Disposeable {
String USAGE_VIEW = "UsageView.new";
void appendUsage(Usage usage);
void removeUsage(Usage usage);
void includeUsages(Usage[] usages);
void excludeUsages(Usage[] usages);
void selectUsages(Usage[] usages);
void close();
boolean isSearchInProgress();
@@ -36,6 +38,8 @@ public interface UsageView extends Disposeable {
UsageViewPresentation getPresentation();
Set<Usage> getExcludedUsages();
Set<Usage> getSelectedUsages();
Set<Usage> getUsages();
JComponent getComponent();
}
@@ -21,9 +21,16 @@ public interface UsageViewManager {
boolean showPanelIfOnlyOneUsage,
boolean showNotFoundMessage, UsageViewPresentation presentation);
UsageView searchAndShowUsages(UsageTarget[] searchFor,
Factory<UsageSearcher> searcherFactory,
boolean showPanelIfOnlyOneUsage,
boolean showNotFoundMessage, UsageViewPresentation presentation,
Factory<ProgressIndicator> progressIndicatorFactory);
interface UsageViewStateListener {
void usageViewCreated(UsageView usageView);
void findingUsagesFinished();
}
void searchAndShowUsages(UsageTarget[] searchFor,
Factory<UsageSearcher> searcherFactory,
boolean showPanelIfOnlyOneUsage,
boolean showNotFoundMessage,
UsageViewPresentation presentation,
Factory<ProgressIndicator> progressIndicatorFactory,
UsageViewStateListener listener);
}
@@ -72,6 +72,36 @@ class GroupNode extends Node implements Navigatable {
return null;
}
public boolean removeUsage(UsageNode usage) {
final Collection<GroupNode> groupNodes = mySubgroupNodes.values();
for(Iterator<GroupNode> i = groupNodes.iterator();i.hasNext();) {
final GroupNode groupNode = i.next();
if(groupNode.removeUsage(usage)) {
doUpdate();
if (groupNode.getRecursiveUsageCount() == 0) {
myTreeModel.removeNodeFromParent(groupNode);
mySubgroupNodes.remove(groupNode);
}
return true;
}
}
if (myUsageNodes.remove(usage)) {
doUpdate();
return true;
}
return false;
}
private void doUpdate() {
--myRecursiveUsageCount;
myTreeModel.reload(this);
}
public UsageNode addUsage(Usage usage) {
try {
UsageNode mergedWith = tryMerge(usage);
@@ -28,9 +28,7 @@ import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.util.ui.Tree;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -473,6 +471,16 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
}
}
public void removeUsage(Usage usage) {
final UsageNode node = myUsageNodes.get(usage);
if (node != null) {
((DefaultTreeModel)myTree.getModel()).removeNodeFromParent (node);
myUsageNodes.remove(usage);
((GroupNode)myTree.getModel().getRoot()).removeUsage(node);
}
}
public void includeUsages(Usage[] usages) {
for (int i = 0; i < usages.length; i++) {
final UsageNode node = myUsageNodes.get(usages[i]);
@@ -493,6 +501,23 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
updateImmediately();
}
public void selectUsages(Usage[] usages) {
if (usages == null) return;
List<TreePath> pathes = new LinkedList<TreePath>();
for (int i = 0; i < usages.length; i++) {
final UsageNode node = myUsageNodes.get(usages[i]);
if (node != null) {
pathes.add(new TreePath(node.getPath()));
}
}
myTree.setSelectionPaths(pathes.toArray(new TreePath[pathes.size()]));
if (pathes.size() > 0) myTree.scrollPathToVisible(pathes.get(0));
}
public JComponent getComponent() {
return myRootPanel;
}
@@ -710,7 +735,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
return node instanceof Node ? (Node)node : null;
}
private Usage[] getSelectedUsages() {
public Set<Usage> getSelectedUsages() {
TreePath[] selectionPaths = myTree.getSelectionPaths();
if (selectionPaths == null) return null;
@@ -721,7 +746,13 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
collectUsages(node, usages);
}
return usages.toArray(new Usage[usages.size()]);
return usages;
}
public Set<Usage> getUsages() {
final LinkedHashSet<Usage> usages = new LinkedHashSet<Usage>();
collectUsages((DefaultMutableTreeNode)myTree.getModel().getRoot(), usages);
return usages;
}
private void collectUsages(DefaultMutableTreeNode node, Set<Usage> usages) {
@@ -837,7 +868,8 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra
}
if (dataId.equals(USAGES)) {
return getSelectedUsages();
final Set<Usage> selectedUsages = getSelectedUsages();
return selectedUsages.toArray(new Usage[selectedUsages.size()]);
}
if (dataId.equals(USAGE_TARGETS)) {
@@ -67,7 +67,7 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
final Application application = ApplicationManager.getApplication();
application.runProcessWithProgressSynchronously(
createSearchRunnable(usageView, presentation, searchFor, searcherFactory, showNotFoundMessage, showPanelIfOnlyOneUsage, application),
createSearchRunnable(usageView, presentation, searchFor, searcherFactory, showNotFoundMessage, showPanelIfOnlyOneUsage, null),
getProgressTitle(presentation),
true,
myProject
@@ -82,19 +82,22 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
final Factory<UsageSearcher> searcherFactory,
final boolean showNotFoundMessage,
final boolean showPanelIfOnlyOneUsage,
final Application application) {
return new SearchForUsagesRunnable(usageView, presentation, searchFor, searcherFactory, showNotFoundMessage, showPanelIfOnlyOneUsage, application);
final UsageViewManager.UsageViewStateListener listener) {
return new SearchForUsagesRunnable(usageView, presentation, searchFor, searcherFactory, showNotFoundMessage, showPanelIfOnlyOneUsage, listener);
}
public UsageView searchAndShowUsages(UsageTarget[] searchFor,
public void searchAndShowUsages(UsageTarget[] searchFor,
Factory<UsageSearcher> searcherFactory,
boolean showPanelIfOnlyOneUsage,
boolean showNotFoundMessage,
UsageViewPresentation presentation,
final Factory<ProgressIndicator> progressIndicatorFactory) {
final Factory<ProgressIndicator> progressIndicatorFactory,
UsageViewManager.UsageViewStateListener listener
) {
final UsageViewImpl[] usageView = new UsageViewImpl[]{null};
final Application application = ApplicationManager.getApplication();
final SearchForUsagesRunnable runnable = (SearchForUsagesRunnable)createSearchRunnable(usageView, presentation, searchFor, searcherFactory, showNotFoundMessage, showPanelIfOnlyOneUsage, application);
final SearchForUsagesRunnable runnable = (SearchForUsagesRunnable)createSearchRunnable(
usageView, presentation, searchFor, searcherFactory, showNotFoundMessage, showPanelIfOnlyOneUsage, listener
);
UsageViewImplUtil.runProcessWithProgress(
progressIndicatorFactory.create(),
@@ -110,8 +113,6 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
}
}
);
return usageView[0];
}
static String getProgressTitle(UsageViewPresentation presentation) {
@@ -122,7 +123,7 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
private void activateToolwindow() {
ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND);
if (!toolWindow.isActive()) toolWindow.activate(null);
if (!toolWindow.isActive()) toolWindow.show(null);
}
private void appendUsages(Usage[] foundUsages, UsageViewImpl usageView) {
@@ -154,7 +155,7 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
private final Factory<UsageSearcher> mySearcherFactory;
private final boolean myShowNotFoundMessage;
private final boolean myShowPanelIfOnlyOneUsage;
private final Application myApplication;
private UsageViewManager.UsageViewStateListener myListener;
public SearchForUsagesRunnable(final UsageViewImpl[] usageView,
final UsageViewPresentation presentation,
@@ -162,14 +163,14 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
final Factory<UsageSearcher> searcherFactory,
final boolean showNotFoundMessage,
final boolean showPanelIfOnlyOneUsage,
final Application application) {
final UsageViewManager.UsageViewStateListener listener) {
myUsageView = usageView;
myPresentation = presentation;
mySearchFor = searchFor;
mySearcherFactory = searcherFactory;
myShowNotFoundMessage = showNotFoundMessage;
myShowPanelIfOnlyOneUsage = showPanelIfOnlyOneUsage;
myApplication = application;
myListener = listener;
}
private void activateView() {
@@ -179,6 +180,7 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
SwingUtilities.invokeLater(new Runnable() {
public void run() {
addContent(myUsageView[0], myPresentation);
if (myListener!=null) myListener.usageViewCreated(myUsageView[0]);
activateToolwindow();
}
});
@@ -222,7 +224,7 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
private void endSearchForUsages() {
if (myUsageCount == 0 && myShowNotFoundMessage) {
myApplication.invokeLater(new Runnable() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
Messages.showMessageDialog(myProject, "No " + myPresentation.getUsagesString() + " found in " + myPresentation.getScopeText(), "Information",
Messages.getInformationIcon());
@@ -241,6 +243,10 @@ public class UsageViewManagerImpl implements UsageViewManager, ProjectComponent
else {
myUsageView[0].setSearchInProgress(false);
}
if (myListener != null) {
myListener.findingUsagesFinished();
}
}
}
}
@@ -3,6 +3,7 @@ package com.intellij.find.findInProject;
import com.intellij.find.FindManager;
import com.intellij.find.FindModel;
import com.intellij.find.FindProgressIndicator;
import com.intellij.find.FindSettings;
import com.intellij.find.impl.FindInProjectUtil;
import com.intellij.find.replaceInProject.ReplaceInProjectManager;
import com.intellij.openapi.actionSystem.DataConstants;
@@ -12,19 +13,14 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.util.Factory;
import com.intellij.psi.PsiDirectory;
import com.intellij.ui.content.Content;
import com.intellij.usageView.*;
import com.intellij.usageView.UsageViewManager;
import com.intellij.usages.*;
import com.intellij.navigation.ItemPresentation;
import com.intellij.util.Processor;
import javax.swing.*;
import java.util.ArrayList;
public class FindInProjectManager implements ProjectComponent {
@@ -108,88 +104,14 @@ public class FindInProjectManager implements ProjectComponent {
}
com.intellij.usages.UsageViewManager manager = myProject.getComponent(com.intellij.usages.UsageViewManager.class);
class StringUsageTarget implements UsageTarget {
private String myStringToFind;
private ItemPresentation myItemPresentation = new ItemPresentation() {
public String getPresentableText() {
return "String '" + myStringToFind + "'";
}
public String getLocationString() {
return myStringToFind + "!!";
}
public TextAttributesKey getTextAttributesKey() {
return null;
}
public Icon getIcon(boolean open) {
return null;
}
};
public StringUsageTarget(String _stringToFind) {
myStringToFind = _stringToFind;
}
public void findUsages() {
throw new UnsupportedOperationException();
}
public void findUsagesInEditor(FileEditor editor) {
throw new UnsupportedOperationException();
}
public boolean isValid() {
return true;
}
public boolean isReadOnly() {
return true;
}
public VirtualFile[] getFiles() {
throw new UnsupportedOperationException();
}
public String getName() {
return myStringToFind;
}
public ItemPresentation getPresentation() {
return myItemPresentation;
}
public FileStatus getFileStatus() {
return null;
}
public void navigate(boolean requestFocus) {
throw new UnsupportedOperationException();
}
public boolean canNavigate() {
return false;
}
public boolean canNavigateToSource() {
return false;
}
}
if (manager!=null) {
findManager.getFindInProjectModel().copyFrom(findModel);
final FindModel findModelCopy = (FindModel)findModel.clone();
final UsageViewPresentation presentation = new UsageViewPresentation();
presentation.setScopeText(FindInProjectUtil.getTitleForScope(findModelCopy));
presentation.setUsagesString("occurrences of '" + findModelCopy.getStringToFind() + "'");
presentation.setOpenInNewTab(myToOpenInNewTab);
presentation.setCodeUsages(false);
final UsageViewPresentation presentation = FindInProjectUtil.setupViewPresentation(myToOpenInNewTab, findModelCopy);
manager.searchAndShowUsages(
new UsageTarget[] { new StringUsageTarget(findModel.getStringToFind()) },
new UsageTarget[] { new FindInProjectUtil.StringUsageTarget(findModel.getStringToFind()) },
new Factory<UsageSearcher>() {
public UsageSearcher create() {
return new UsageSearcher() {
@@ -217,89 +139,19 @@ public class FindInProjectManager implements ProjectComponent {
};
}
},
false,
!FindSettings.getInstance().isSkipResultsWithOneUsage(),
true,
presentation,
new Factory<ProgressIndicator>() {
public ProgressIndicator create() {
return new FindProgressIndicator(myProject, FindInProjectUtil.getTitleForScope(findModelCopy));
}
}
public ProgressIndicator create() {
return new FindProgressIndicator(myProject, FindInProjectUtil.getTitleForScope(findModelCopy));
}
},
null
);
}
//AsyncFindUsagesCommand command = new AsyncFindUsagesCommand() {
// FindProgressIndicator progress;
//
// public void findUsages(final AsyncFindUsagesProcessListener consumer) {
// myIsFindInProgress = true;
// findManager.getFindInProjectModel().copyFrom(findModel);
//
// // [jeka] should use a _copy_ of findModel, because of RefreshCommand, findModel is reused by later FindUsages commands!!!!
// final FindModel findModelCopy = (FindModel)findModel.clone();
// progress = new FindProgressIndicator(myProject, FindInProjectUtil.getTitleForScope(findModelCopy));
// final Runnable findUsagesRunnable = new Runnable() {
// public void run() {
// FindInProjectUtil.findUsages(findModelCopy, psiDirectory, myProject, consumer);
// }
// };
//
// Runnable showUsagesPanelRunnable = new Runnable() {
// public void run() {
// myIsFindInProgress = false;
// if (consumer.getCount()==0) {
// if (!progress.isCanceled()) {
// String title = "No occurrences of '" + findModel.getStringToFind() + "' found in " + FindInProjectUtil.getTitleForScope(findModelCopy);
//
// Messages.showMessageDialog(
// myProject,
// title,
// "Find in Path",
// Messages.getInformationIcon()
// );
// }
// }
// }
// };
//
// FindInProjectUtil.runProcessWithProgress(progress, findUsagesRunnable, showUsagesPanelRunnable, myProject);
// }
//
// public void stopAsyncSearch() {
// progress.cancel();
// }
//};
//
//showUsagesPanel(
// new FindInProjectViewDescriptor(findModel,command),
// toOpenInNewTab[0]
//);
}
//private void showUsagesPanel(final FindInProjectViewDescriptor viewDescriptor, boolean toOpenInNewTab) {
// String stringToFind = viewDescriptor.getFindModel().getStringToFind();
// String name = "Search result";
// if (stringToFind != null) {
// if (stringToFind.length() > 15) {
// stringToFind = stringToFind.substring(0, 15) + "...";
// }
// name = "Occurrences of '"+stringToFind + "'";
// }
//
// if (viewDescriptor.getFindModel().isMultipleFiles() ) {
// name += " in " +FindInProjectUtil.getTitleForScope(viewDescriptor.getFindModel());
// }
// UsageViewManager.getInstance(myProject).addContent(name, viewDescriptor, true, toOpenInNewTab, true, new ProgressFactory () {
// public ProgressIndicator createProgress() {
// return new FindProgressIndicator(myProject, FindInProjectUtil.getTitleForScope(viewDescriptor.getFindModel()));
// }
//
// public boolean continueOnCancel() {
// return true;
// }
// });
//}
public boolean isWorkInProgress() {
return myIsFindInProgress;
}
@@ -307,4 +159,4 @@ public class FindInProjectManager implements ProjectComponent {
public boolean isEnabled () {
return !myIsFindInProgress && !ReplaceInProjectManager.getInstance(myProject).isWorkInProgress();
}
}
}
+29 -9
View File
@@ -9,7 +9,6 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.*;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PatternUtil;
import com.intellij.openapi.module.ModuleManager;
@@ -17,7 +16,6 @@ import com.intellij.openapi.module.Module;
import com.intellij.psi.PsiDirectory;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.StateRestoringCheckBox;
import com.intellij.util.PatternUtil;
import javax.swing.*;
import java.awt.*;
@@ -52,6 +50,7 @@ final class FindDialog extends DialogWrapper {
private FixedSizeButton mySelectDirectoryButton;
private StateRestoringCheckBox useFileFilter;
private ComboBox myFileFilter;
protected JCheckBox myCbToSkipResultsWhenOneUsage;
private final Project myProject;
public FindDialog(Project project, FindModel model){
@@ -234,6 +233,15 @@ final class FindDialog extends DialogWrapper {
gbConstraints.gridwidth = GridBagConstraints.REMAINDER;
optionsPanel.add(createFilterPanel(),gbConstraints);
if (!myModel.isReplaceState()) {
myCbToSkipResultsWhenOneUsage = new StateRestoringCheckBox(
"Skip results tab with one usage",
FindSettings.getInstance().isSkipResultsWithOneUsage()
);
myCbToSkipResultsWhenOneUsage.setMnemonic('k');
optionsPanel.add(myCbToSkipResultsWhenOneUsage, gbConstraints);
}
}
if (myModel.isOpenInNewTabVisible()){
@@ -353,9 +361,20 @@ final class FindDialog extends DialogWrapper {
}
}
if (myCbToSkipResultsWhenOneUsage != null){
FindSettings.getInstance().setSkipResultsWithOneUsage(
isSkipResultsWhenOneUsage()
);
}
super.doOKAction();
}
public boolean isSkipResultsWhenOneUsage() {
return myCbToSkipResultsWhenOneUsage!=null &&
myCbToSkipResultsWhenOneUsage.isSelected();
}
private JPanel createFindOptionsPanel() {
JPanel findOptionsPanel = new JPanel();
findOptionsPanel.setBorder(IdeBorderFactory.createTitledBorder("Options"));
@@ -668,15 +687,18 @@ final class FindDialog extends DialogWrapper {
FindSettings findSettings = FindSettings.getInstance();
model.setCaseSensitive(myCbCaseSensitive.isSelected());
findSettings.setCaseSensitive(myCbCaseSensitive.isSelected());
if (model.isReplaceState()) {
model.setPreserveCase(myCbPreserveCase.isSelected());
findSettings.setPreserveCase(myCbPreserveCase.isSelected());
}
model.setWholeWordsOnly(myCbWholeWordsOnly.isSelected());
findSettings.setWholeWordsOnly(myCbWholeWordsOnly.isSelected());
model.setRegularExpressions(myCbRegularExpressions.isSelected());
findSettings.setRegularExpressions(myCbRegularExpressions.isSelected());
model.setStringToFind((String)myInputComboBox.getSelectedItem());
if (model.isReplaceState()){
model.setPromptOnReplace(true);
model.setReplaceAll(false);
@@ -686,6 +708,7 @@ final class FindDialog extends DialogWrapper {
}
model.setStringToReplace(stringToReplace);
}
if (!model.isMultipleFiles()){
model.setForward(myRbForward.isSelected());
findSettings.setForward(myRbForward.isSelected());
@@ -698,8 +721,7 @@ final class FindDialog extends DialogWrapper {
if (myCbToOpenInNewTab != null){
model.setOpenInNewTab(myCbToOpenInNewTab.isSelected());
}
model.setWithSubdirectories(myCbWithSubdirectories.isSelected());
findSettings.setWithSubdirectories(myCbWithSubdirectories.isSelected());
model.setProjectScope(myRbProject.isSelected());
model.setDirectoryName(null);
model.setModuleName(null);
@@ -707,10 +729,8 @@ final class FindDialog extends DialogWrapper {
if (myRbDirectory.isSelected()){
String directory = getDirectory();
model.setDirectoryName(directory == null ? "" : directory);
if (directory==null) {
//model.setWithSubdirectories(myCbWithSubdirectories.isSelected());
//findSettings.setWithSubdirectories(myCbWithSubdirectories.isSelected());
}
model.setWithSubdirectories(myCbWithSubdirectories.isSelected());
findSettings.setWithSubdirectories(myCbWithSubdirectories.isSelected());
} else if (myRbModule.isSelected()) {
model.setModuleName((String)myModuleComboBox.getSelectedItem());
}
@@ -776,7 +796,7 @@ final class FindDialog extends DialogWrapper {
myModuleComboBox.setEnabled(true);
myModuleComboBox.setSelectedItem(myModel.getModuleName());
}
myCbWithSubdirectories.setSelected(myModel.isWithSubdirectories());
if (myModel.getFileFilter()!=null && myModel.getFileFilter().length() > 0) {
@@ -1,7 +1,11 @@
package com.intellij.find.impl;
import com.intellij.Patches;
import com.intellij.navigation.ItemPresentation;
import com.intellij.usages.impl.UsageViewImplUtil;
import com.intellij.usages.UsageTarget;
import com.intellij.usages.UsageViewPresentation;
import com.intellij.usages.Usage;
import com.intellij.find.FindManager;
import com.intellij.find.FindModel;
import com.intellij.find.FindResult;
@@ -9,9 +13,10 @@ import com.intellij.openapi.actionSystem.DataConstants;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.ex.DataConstantsEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
@@ -28,14 +33,18 @@ import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.psi.*;
import com.intellij.usageView.AsyncFindUsagesProcessListener;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.PatternUtil;
import javax.swing.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Iterator;
import java.util.regex.Pattern;
public class FindInProjectUtil {
@@ -294,4 +303,96 @@ public class FindInProjectUtil {
return result.toString();
}
public static UsageViewPresentation setupViewPresentation(final boolean toOpenInNewTab, final FindModel findModelCopy) {
final UsageViewPresentation presentation = new UsageViewPresentation();
presentation.setScopeText(getTitleForScope(findModelCopy));
presentation.setTabText("Occurrences of '" + findModelCopy.getStringToFind() + "'");
presentation.setUsagesString("occurrences of '" + findModelCopy.getStringToFind() + "'");
presentation.setOpenInNewTab(toOpenInNewTab);
presentation.setCodeUsages(false);
return presentation;
}
public static boolean hasReadOnlyUsages(final Set<Usage> usages) {
for (Iterator<Usage> iterator = usages.iterator(); iterator.hasNext();) {
Usage usage = iterator.next();
if (usage.isReadOnly()) return true;
}
return false;
}
public static class StringUsageTarget implements UsageTarget {
private String myStringToFind;
private ItemPresentation myItemPresentation = new ItemPresentation() {
public String getPresentableText() {
return "String '" + myStringToFind + "'";
}
public String getLocationString() {
return myStringToFind + "!!";
}
public Icon getIcon(boolean open) {
return null;
}
public TextAttributesKey getTextAttributesKey() {
return null;
}
};
public StringUsageTarget(String _stringToFind) {
myStringToFind = _stringToFind;
}
public void findUsages() {
throw new UnsupportedOperationException();
}
public void findUsagesInEditor(FileEditor editor) {
throw new UnsupportedOperationException();
}
public boolean isValid() {
return true;
}
public boolean isReadOnly() {
return true;
}
public VirtualFile[] getFiles() {
throw new UnsupportedOperationException();
}
public String getName() {
return myStringToFind;
}
public ItemPresentation getPresentation() {
return myItemPresentation;
}
public FileStatus getFileStatus() {
return null;
}
public void navigate(boolean requestFocus) {
throw new UnsupportedOperationException();
}
public boolean canNavigate() {
return false;
}
public boolean canNavigateToSource() {
return false;
}
}
}
@@ -122,6 +122,10 @@ public class FindManagerImpl extends FindManager implements ProjectComponent {
}
if (model.isMultipleFiles() && !model.isProjectScope()){
FindSettings.getInstance().addDirectory(model.getDirectoryName());
if (model.getDirectoryName()!=null) {
myFindInProjectModel.setWithSubdirectories(model.isWithSubdirectories());
}
}
return true;
}
@@ -4,8 +4,6 @@ package com.intellij.find.replaceInProject;
import com.intellij.find.*;
import com.intellij.find.findInProject.FindInProjectManager;
import com.intellij.find.impl.FindInProjectUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataConstants;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
@@ -13,22 +11,26 @@ import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.usageView.*;
import com.intellij.usages.*;
import com.intellij.usages.UsageViewManager;
import com.intellij.usages.UsageView;
import com.intellij.util.Processor;
import javax.swing.*;
import javax.swing.tree.TreePath;
import java.util.Set;
import java.util.Iterator;
public class ReplaceInProjectManager implements ProjectComponent {
private Project myProject;
@@ -54,6 +56,30 @@ public class ReplaceInProjectManager implements ProjectComponent {
myProject = project;
}
static class ReplaceContext {
private com.intellij.usages.UsageView usageView;
private FindModel findModel;
private Set<Usage> excludedSet;
ReplaceContext(com.intellij.usages.UsageView _usageView, FindModel _findModel) {
usageView = _usageView;
findModel = _findModel;
}
public FindModel getFindModel() {
return findModel;
}
public com.intellij.usages.UsageView getUsageView() {
return usageView;
}
public Set<Usage> getExcludedSet() {
if (excludedSet == null) excludedSet = usageView.getExcludedUsages();
return excludedSet;
}
}
public void replaceInProject(DataContext dataContext) {
final FindManager findManager = FindManager.getInstance(myProject);
final FindModel findModel = (FindModel) findManager.getFindInProjectModel().clone();
@@ -75,66 +101,88 @@ public class ReplaceInProjectManager implements ProjectComponent {
return;
}
class AsyncFindUsagesCommandImpl implements AsyncFindUsagesCommand {
ReplaceInProjectViewDescriptor viewDescriptor;
UsageView usagesPanel;
ProgressIndicator progress;
com.intellij.usages.UsageViewManager manager = myProject.getComponent(com.intellij.usages.UsageViewManager.class);
public void findUsages(final AsyncFindUsagesProcessListener consumer) {
progress = new FindProgressIndicator (myProject, FindInProjectUtil.getTitleForScope(findModel));
final Runnable findUsagesRunnable = new Runnable() {
public void run() {
FindInProjectUtil.findUsages(findManager.getFindInProjectModel(), psiDirectory, myProject, consumer);
}
};
final Runnable showUsagesPanelRunnable = new Runnable() {
public void run() {
myIsFindInProgress = false;
if (manager!=null) {
final UsageViewPresentation presentation = FindInProjectUtil.setupViewPresentation(true, findModel);
if (consumer.getCount()!=0 && findManager.getFindInProjectModel().isPromptOnReplace()){
replaceWithPrompt(usagesPanel, viewDescriptor);
final ReplaceContext context[] = new ReplaceContext[1];
manager.searchAndShowUsages(
new UsageTarget[] { new FindInProjectUtil.StringUsageTarget(findModel.getStringToFind()) },
new Factory<UsageSearcher>() {
public UsageSearcher create() {
return new UsageSearcher() {
public void generate(final Processor<Usage> processor) {
myIsFindInProgress = true;
FindInProjectUtil.findUsages(findModel, psiDirectory, myProject, new AsyncFindUsagesProcessListener() {
int count;
public void foundUsage(UsageInfo info) {
++count;
processor.process(new UsageInfo2UsageAdapter(info));
}
public void findUsagesCompleted() {
}
public int getCount() {
return count;
}
});
myIsFindInProgress = false;
}
};
}
};
Runnable showUsagesPanelRunnable1 = new Runnable() {
public void run() {
// This is important since not all usages are flushed during async processing!
SwingUtilities.invokeLater(showUsagesPanelRunnable);
},
true,
true,
presentation,
new Factory<ProgressIndicator>() {
public ProgressIndicator create() {
return new FindProgressIndicator(myProject, FindInProjectUtil.getTitleForScope(findModel));
}
},
new UsageViewManager.UsageViewStateListener() {
public void usageViewCreated(UsageView usageView) {
context[0] = new ReplaceContext(usageView,findModel);
addReplaceActions(context[0]);
}
};
myIsFindInProgress = true;
findManager.getFindInProjectModel().copyFrom(findModel);
FindInProjectUtil.runProcessWithProgress(progress, findUsagesRunnable, showUsagesPanelRunnable1, myProject);
public void findingUsagesFinished() {
if (context[0]!=null && findManager.getFindInProjectModel().isPromptOnReplace()){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
replaceWithPrompt(context[0]);
}
});
}
}
}
public void stopAsyncSearch() {
progress.cancel();
}
};
AsyncFindUsagesCommandImpl findUsagesCommand = new AsyncFindUsagesCommandImpl();
ReplaceInProjectViewDescriptor viewDescriptor = new ReplaceInProjectViewDescriptor(findModel, findUsagesCommand);
UsageView usagesPanel = showUsagesPanel(viewDescriptor);
findUsagesCommand.viewDescriptor = viewDescriptor;
findUsagesCommand.usagesPanel = usagesPanel;
);
}
}
private void replaceWithPrompt(final UsageView usageView, final ReplaceInProjectViewDescriptor viewDescriptor) {
final UsageInfo[] usages = usageView.getUsages();
private void replaceWithPrompt(final ReplaceContext replaceContext) {
final Set<Usage> _usages = replaceContext.getUsageView().getUsages();
if (UsageViewUtil.hasReadOnlyUsages(usages)){
if (FindInProjectUtil.hasReadOnlyUsages(_usages)){
WindowManager.getInstance().getStatusBar(myProject).setInfo("Occurrences found in read-only files");
return;
}
usageView.expandAll();
for(int i = 0; i < usages.length; i++){
final PsiFile psiFile = usages[i].getElement().getContainingFile();
final Usage[] usages;
_usages.toArray(usages = new Usage[_usages.size()]);
//usageView.expandAll();
for(int i = 0; i < usages.length; ++i){
final Usage usage = usages[i];
final UsageInfo usageInfo = ((UsageInfo2UsageAdapter)usage).getUsageInfo();
final PsiFile psiFile = usageInfo.getElement().getContainingFile();
if (!psiFile.isWritable()) continue;
final UsageInfo usageInfo = usages[i];
Runnable selectOnEditorRunnable = new Runnable() {
public void run() {
@@ -147,27 +195,18 @@ public class ReplaceInProjectManager implements ProjectComponent {
}
}
).booleanValue()) {
int startOffset = usageView.getTextOffset(usageInfo);
int endOffset = usageView.getTextEndOffset(usageInfo);
Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (endOffset <= document.getTextLength()) {
OpenFileDescriptor descriptor = new OpenFileDescriptor(myProject, virtualFile, startOffset);
FileEditorManager.getInstance(myProject).openTextEditor(descriptor, false);
descriptor = new OpenFileDescriptor(myProject, virtualFile, endOffset);
Editor editor = FileEditorManager.getInstance(myProject).openTextEditor(descriptor, false);
if (editor != null) {
editor.getSelectionModel().setSelection(startOffset, endOffset);
}
usageView.selectUsage(usageInfo);
if (usage.isValid()) {
usage.highlightInEditor();
replaceContext.getUsageView().selectUsages(new Usage[]{usage});
}
}
}
};
CommandProcessor.getInstance().executeCommand(myProject, selectOnEditorRunnable, "Select on Editor", null);
String title = "Replace Usage " + (i + 1) + " of " + usages.length + " Found";
int result = FindManager.getInstance(myProject).showPromptDialog(viewDescriptor.getFindModel(), title);
String title = "Replace Usage " + (i+1) + " of " + usages.length + " Found";
int result = FindManager.getInstance(myProject).showPromptDialog(replaceContext.getFindModel(), title);
if (result == PromptResult.CANCEL){
return;
@@ -180,68 +219,54 @@ public class ReplaceInProjectManager implements ProjectComponent {
if (result == PromptResult.OK){
Runnable runnable = new Runnable() {
public void run() {
doReplace(usageView, usages[currentNumber], viewDescriptor);
usageView.removeUsage(usages[currentNumber]);
doReplace(replaceContext, usage);
replaceContext.getUsageView().removeUsage(usage);
}
};
CommandProcessor.getInstance().executeCommand(myProject, runnable, "Replace", null);
if (usageView.getUsagesNodeCount() == 0){
UsageViewManager.getInstance(myProject).closeContent(usageView);
if ((i + 1) == usages.length){
replaceContext.getUsageView().close();
return;
}
}
if (result == PromptResult.ALL_IN_THIS_FILE){
final int[] nextNumber = new int[1];
Runnable runnable = new Runnable() {
public void run() {
int j = currentNumber;
for(; j < usages.length; j++){
PsiFile otherPsiFile = usages[j].getElement().getContainingFile();
final Usage usage = usages[j];
final UsageInfo usageInfo = ((UsageInfo2UsageAdapter)usage).getUsageInfo();
PsiFile otherPsiFile = usageInfo.getElement().getContainingFile();
if (!otherPsiFile.equals(psiFile)){
break;
}
doReplace(usageView, usages[j], viewDescriptor);
usageView.removeUsage(usages[j]);
doReplace(replaceContext, usage);
replaceContext.getUsageView().removeUsage(usage);
}
if (j >= usages.length){
UsageViewManager.getInstance(myProject).closeContent(usageView);
if (j == usages.length){
replaceContext.getUsageView().close();
}
nextNumber[0] = j;
}
};
CommandProcessor.getInstance().executeCommand(myProject, runnable, "Replace", null);
if (usageView.getUsagesNodeCount() == 0){
UsageViewManager.getInstance(myProject).closeContent(usageView);
return;
}
i = nextNumber[0] - 1;
}
if (result == PromptResult.ALL_FILES){
/*
Runnable process = new Runnable() {
public void run() {
for(int j = currentNumber; j < usages.length; j++){
doReplace(usageView, usages[j], viewDescriptor);
}
}
};
Runnable finishProcess = new Runnable() {
public void run() {
ExternalUISupport.getInstance(myProject).closeContent(usageView);
}
};
ProgressUtil.runPsiCommandWithProgress(myProject, process, finishProcess, "Replacing...", "Replace", false);
*/
if (result == PromptResult.ALL_FILES) {
CommandProcessor.getInstance().executeCommand(
myProject, new Runnable() {
public void run() {
for(int j = currentNumber; j < usages.length; j++){
doReplace(usageView, usages[j], viewDescriptor);
for(int i = 0;i < usages.length;++i){
doReplace(replaceContext, usages[i]);
}
UsageViewManager.getInstance(myProject).closeContent(usageView);
replaceContext.getUsageView().close();
}
},
"Replace",
@@ -252,116 +277,74 @@ public class ReplaceInProjectManager implements ProjectComponent {
}
}
private UsageView showUsagesPanel(final ReplaceInProjectViewDescriptor viewDescriptor) {
String name = "Search result";
String stringToFind = viewDescriptor.getFindModel().getStringToFind();
if (stringToFind != null) {
if (stringToFind.length() > 15) {
stringToFind = stringToFind.substring(0, 15) + "...";
}
name = "Occurrences of '" + stringToFind + "'";
if (viewDescriptor.getFindModel().isMultipleFiles() ) {
name += " in " + FindInProjectUtil.getTitleForScope(viewDescriptor.getFindModel());
}
}
UsageView usagesPanel = UsageViewManager.getInstance(myProject).addContent(name, viewDescriptor, false, false, false, new ProgressFactory() {
public ProgressIndicator createProgress() {
return new FindProgressIndicator(myProject, FindInProjectUtil.getTitleForScope(viewDescriptor.getFindModel()));
}
public boolean continueOnCancel() {
return true;
}
});
usagesPanel.addButton(0, new ReplaceSelectedAction(usagesPanel, viewDescriptor));
addReplaceAllAction(usagesPanel, viewDescriptor);
return usagesPanel;
}
private void addReplaceAllAction(final UsageView usageView, final ReplaceInProjectViewDescriptor viewDescriptor) {
private void addReplaceActions(final ReplaceContext replaceContext) {
final Runnable replaceRunnable = new Runnable() {
public void run() {
doReplace(usageView, usageView.getUsages(), viewDescriptor);
doReplace(replaceContext, replaceContext.getUsageView().getUsages());
}
};
usageView.addDoProcessAction(replaceRunnable, "Replace All",null,"&Do Replace All");
replaceContext.getUsageView().addPerformOperationAction(replaceRunnable, "Replace All",null,"Do Replace All", SystemInfo.isMac ? 0 : 'D');
final Runnable replaceSelectedRunnable = new Runnable() {
public void run() {
doReplaceSelected(replaceContext);
}
};
replaceContext.getUsageView().addPerformOperationAction(
replaceSelectedRunnable,
"Replace Selected",
null,
"Replace selected occurrences of \"" + replaceContext.getFindModel().getStringToFind() + "\" to \"" + replaceContext.getFindModel().getStringToReplace() + "\"",
SystemInfo.isMac ? 0 : 'l'
);
}
private class ReplaceSelectedAction extends AnAction {
private UsageView myUsagesPanel;
private ReplaceInProjectViewDescriptor myTreeInfo;
public ReplaceSelectedAction(UsageView usagesPanel, ReplaceInProjectViewDescriptor treeInfo){
super(
"Rep&lace Selected",
"Replace selected occurrences of \"" + treeInfo.getFindModel().getStringToFind() + "\" to \"" + treeInfo.getFindModel().getStringToReplace() + "\"",
null
);
myUsagesPanel=usagesPanel;
myTreeInfo=treeInfo;
}
public void actionPerformed(AnActionEvent event) {
doReplaceSelected(myUsagesPanel, myTreeInfo);
}
public void update(AnActionEvent e) {
e.getPresentation().setEnabled(!myIsFindInProgress);
super.update(e);
private void doReplace(final ReplaceContext replaceContext, Set<Usage> usages) {
for(Iterator<Usage> i = usages.iterator(); i.hasNext();){
doReplace(replaceContext, i.next());
}
}
private void doReplace(UsageView usageView, UsageInfo[] usages, ReplaceInProjectViewDescriptor treeInfo) {
for(int i = 0; i < usages.length; i++){
doReplace(usageView, usages[i], treeInfo);
}
}
private void doReplace(final UsageView usageView, final UsageInfo usage, final ReplaceInProjectViewDescriptor treeInfo) {
private void doReplace(final ReplaceContext replaceContext, final Usage usage) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
if (usageView.isExcluded(usage)){
if (replaceContext.getExcludedSet().contains(usage)){
return;
}
PsiFile file = (PsiFile)usage.getElement();
Project project = file.getProject();
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
RangeMarker marker = ((UsageInfo2UsageAdapter)usage).getRangeMarker();
Document document = marker.getDocument();
if (!document.isWritable()) return;
final int textOffset = usageView.getTextOffset(usage);
final int textOffset = marker.getStartOffset();
if (textOffset < 0 || textOffset >= document.getTextLength()){
return;
}
final int textEndOffset = usageView.getTextEndOffset(usage);
final int textEndOffset = marker.getEndOffset();
if (textEndOffset < 0 || textOffset > document.getTextLength()){
return;
}
FindManager findManager = FindManager.getInstance(myProject);
final CharSequence foundString = document.getCharsSequence().subSequence(textOffset, textEndOffset);
FindResult findResult = findManager.findString(foundString, 0, treeInfo.getFindModel());
FindResult findResult = findManager.findString(foundString, 0, replaceContext.getFindModel());
if (findResult == null || !findResult.isStringFound()){
return;
}
String stringToReplace = findManager.getStringToReplace(foundString.toString(), treeInfo.getFindModel());
String stringToReplace = findManager.getStringToReplace(foundString.toString(), replaceContext.getFindModel());
document.replaceString(textOffset, textEndOffset, stringToReplace);
}
});
}
private void doReplaceSelected(final UsageView usageView, final ReplaceInProjectViewDescriptor treeInfo) {
TreePath[] paths = usageView.getTree().getSelectionPaths();
if (paths == null || paths.length == 0){
private void doReplaceSelected(final ReplaceContext replaceContext) {
final Set<Usage> selectedUsages = replaceContext.getUsageView().getSelectedUsages();
if(selectedUsages == null){
return;
}
final UsageInfo[] usages = usageView.getSelectedUsages();
if(usages == null){
return;
}
if (UsageViewUtil.hasReadOnlyUsages(usages)){
if (FindInProjectUtil.hasReadOnlyUsages(selectedUsages)){
int result = Messages.showOkCancelDialog(
usageView.getTree(),
replaceContext.getUsageView().getComponent(),
"Occurrences found in read-only files.\n" +
"The operation will not affect them.\n" +
"Continue anyway?",
@@ -376,16 +359,16 @@ public class ReplaceInProjectManager implements ProjectComponent {
CommandProcessor.getInstance().executeCommand(
myProject, new Runnable() {
public void run() {
doReplace(usageView, usages, treeInfo);
for (int i = 0; i < usages.length; i++) {
usageView.removeUsage(usages[i]);
doReplace(replaceContext, selectedUsages);
for (Iterator<Usage> i = selectedUsages.iterator(); i.hasNext(); ) {
replaceContext.getUsageView().removeUsage(i.next());
}
if (usageView.getUsagesNodeCount() == 0){
UsageViewManager.getInstance(myProject).closeContent(usageView);
if (replaceContext.getUsageView().getUsages().size() == 0){
replaceContext.getUsageView().close();
return;
}
usageView.setFocused();
replaceContext.getUsageView().getComponent().requestFocus();
}
},
"Replace",