diff options
Diffstat (limited to 'platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui')
5 files changed, 593 insertions, 0 deletions
diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceCommand.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceCommand.java new file mode 100644 index 000000000000..1b704f7c968e --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceCommand.java @@ -0,0 +1,40 @@ +package com.intellij.structuralsearch.plugin.replace.ui; + +import com.intellij.openapi.project.Project; +import com.intellij.structuralsearch.MatchResult; +import com.intellij.structuralsearch.plugin.StructuralSearchPlugin; +import com.intellij.structuralsearch.plugin.ui.SearchCommand; +import com.intellij.usages.Usage; + +/** + * Created by IntelliJ IDEA. + * User: Maxim.Mossienko + * Date: Mar 31, 2004 + * Time: 3:54:03 PM + * To change this template use File | Settings | File Templates. + */ +public class ReplaceCommand extends SearchCommand { + + public ReplaceCommand(Project project, ReplaceUsageViewContext context) { + super( project, context ); + } + + protected void findStarted() { + super.findStarted(); + + StructuralSearchPlugin.getInstance(project).setReplaceInProgress(true); + } + + protected void findEnded() { + StructuralSearchPlugin.getInstance(project).setReplaceInProgress( false ); + + super.findEnded(); + } + + protected void foundUsage(MatchResult result, Usage usage) { + super.foundUsage(result, usage); + + final ReplaceUsageViewContext replaceUsageViewContext = ((ReplaceUsageViewContext)context); + replaceUsageViewContext.addReplaceUsage(usage,replaceUsageViewContext.getReplacer().buildReplacement(result)); + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceConfiguration.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceConfiguration.java new file mode 100644 index 000000000000..fa9beaa36a23 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceConfiguration.java @@ -0,0 +1,46 @@ +package com.intellij.structuralsearch.plugin.replace.ui; + +import org.jdom.Element; +import com.intellij.structuralsearch.plugin.ui.Configuration; +import com.intellij.structuralsearch.plugin.replace.ReplaceOptions; +import com.intellij.structuralsearch.MatchOptions; + +/** + * @author Maxim.Mossienko + * Date: Apr 14, 2004 + * Time: 4:41:37 PM + */ +public class ReplaceConfiguration extends Configuration { + private final ReplaceOptions options = new ReplaceOptions(); + public static final String REPLACEMENT_VARIABLE_SUFFIX = "$replacement"; + + public ReplaceOptions getOptions() { + return options; + } + + public MatchOptions getMatchOptions() { + return options.getMatchOptions(); + } + + public void readExternal(Element element) { + super.readExternal(element); + options.readExternal(element); + } + + public void writeExternal(Element element) { + super.writeExternal(element); + options.writeExternal(element); + } + + public boolean equals(Object configuration) { + if (!super.equals(configuration)) return false; + if (configuration instanceof ReplaceConfiguration) { + return options.equals(((ReplaceConfiguration)configuration).options); + } + return false; + } + + public int hashCode() { + return options.hashCode(); + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceDialog.java new file mode 100644 index 000000000000..b02fadab8245 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceDialog.java @@ -0,0 +1,195 @@ +package com.intellij.structuralsearch.plugin.replace.ui; + +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.template.impl.Variable; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.ui.Splitter; +import com.intellij.structuralsearch.MalformedPatternException; +import com.intellij.structuralsearch.ReplacementVariableDefinition; +import com.intellij.structuralsearch.SSRBundle; +import com.intellij.structuralsearch.UnsupportedPatternException; +import com.intellij.structuralsearch.plugin.replace.ReplaceOptions; +import com.intellij.structuralsearch.plugin.replace.impl.Replacer; +import com.intellij.structuralsearch.plugin.ui.*; +import com.intellij.util.containers.hash.LinkedHashMap; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +// Class to show the user the request for search + +@SuppressWarnings({"RefusedBequest"}) +public class ReplaceDialog extends SearchDialog { + private Editor replaceCriteriaEdit; + private JCheckBox shortenFQN; + private JCheckBox formatAccordingToStyle; + private JCheckBox useStaticImport; + + private String mySavedEditorText; + + protected String getDefaultTitle() { + return SSRBundle.message("structural.replace.title"); + } + + protected JComponent createEditorContent() { + JPanel result = new JPanel(new BorderLayout()); + Splitter p; + + result.add(BorderLayout.CENTER, p = new Splitter(true, 0.5f)); + p.setFirstComponent(super.createEditorContent()); + + replaceCriteriaEdit = createEditor(searchContext, mySavedEditorText != null ? mySavedEditorText : ""); + JPanel replace = new JPanel(new BorderLayout()); + replace.add(BorderLayout.NORTH, new JLabel(SSRBundle.message("replacement.template.label"))); + replace.add(BorderLayout.CENTER, replaceCriteriaEdit.getComponent()); + replaceCriteriaEdit.getComponent().setMinimumSize(new Dimension(150, 100)); + + p.setSecondComponent(replace); + + return result; + } + + protected int getRowsCount() { + return super.getRowsCount() + 1; + } + + protected String getDimensionServiceKey() { + return "#com.intellij.structuralsearch.plugin.replace.ui.ReplaceDialog"; + } + + protected void buildOptions(JPanel searchOptions) { + super.buildOptions(searchOptions); + searchOptions.add(UIUtil.createOptionLine(shortenFQN = new JCheckBox( + SSRBundle.message("shorten.fully.qualified.names.checkbox"), true))); + + searchOptions.add(UIUtil.createOptionLine(formatAccordingToStyle = new JCheckBox( + CodeInsightBundle.message("dialog.edit.template.checkbox.reformat.according.to.style"), true))); + + searchOptions.add(UIUtil.createOptionLine(useStaticImport = new JCheckBox( + CodeInsightBundle.message("dialog.edit.template.checkbox.use.static.import"), true))); + } + + protected UsageViewContext createUsageViewContext(Configuration configuration) { + return new ReplaceUsageViewContext(searchContext, configuration); + } + + public ReplaceDialog(SearchContext searchContext) { + super(searchContext); + } + + public ReplaceDialog(SearchContext searchContext, boolean showScope, boolean runFindActionOnClose) { + super(searchContext, showScope, runFindActionOnClose); + } + + + public Configuration createConfiguration() { + ReplaceConfiguration configuration = new ReplaceConfiguration(); + configuration.setName(USER_DEFINED); + return configuration; + } + + protected void disposeEditorContent() { + mySavedEditorText = replaceCriteriaEdit.getDocument().getText(); + EditorFactory.getInstance().releaseEditor(replaceCriteriaEdit); + super.disposeEditorContent(); + } + + public void setValuesFromConfig(Configuration configuration) { + //replaceCriteriaEdit.putUserData(SubstitutionShortInfoHandler.CURRENT_CONFIGURATION_KEY, configuration); + + if (configuration instanceof ReplaceConfiguration) { + final ReplaceConfiguration config = (ReplaceConfiguration)configuration; + final ReplaceOptions options = config.getOptions(); + super.setValuesFromConfig(config); + + UIUtil.setContent(replaceCriteriaEdit, config.getOptions().getReplacement(), 0, replaceCriteriaEdit.getDocument().getTextLength(), + searchContext.getProject()); + + shortenFQN.setSelected(options.isToShortenFQN()); + formatAccordingToStyle.setSelected(options.isToReformatAccordingToStyle()); + useStaticImport.setSelected(options.isToUseStaticImport()); + + ReplaceOptions newReplaceOptions = ((ReplaceConfiguration)model.getConfig()).getOptions(); + newReplaceOptions.clearVariableDefinitions(); + + for (ReplacementVariableDefinition def : options.getReplacementVariableDefinitions()) { + newReplaceOptions.addVariableDefinition((ReplacementVariableDefinition)def.clone()); + } + } + else { + super.setValuesFromConfig(configuration); + + UIUtil.setContent(replaceCriteriaEdit, configuration.getMatchOptions().getSearchPattern(), 0, + replaceCriteriaEdit.getDocument().getTextLength(), searchContext.getProject()); + } + } + + protected void setValuesToConfig(Configuration config) { + super.setValuesToConfig(config); + + final ReplaceConfiguration replaceConfiguration = (ReplaceConfiguration)config; + final ReplaceOptions options = replaceConfiguration.getOptions(); + + options.setMatchOptions(replaceConfiguration.getMatchOptions()); + options.setReplacement(replaceCriteriaEdit.getDocument().getText()); + options.setToShortenFQN(shortenFQN.isSelected()); + options.setToReformatAccordingToStyle(formatAccordingToStyle.isSelected()); + options.setToUseStaticImport(useStaticImport.isSelected()); + } + + protected boolean isRecursiveSearchEnabled() { + return false; + } + + protected java.util.List<Variable> getVariablesFromListeners() { + ArrayList<Variable> vars = getVarsFrom(replaceCriteriaEdit); + List<Variable> searchVars = super.getVariablesFromListeners(); + Map<String, Variable> varsMap = new LinkedHashMap<String, Variable>(searchVars.size()); + + for(Variable var:searchVars) varsMap.put(var.getName(), var); + for(Variable var:vars) { + if (!varsMap.containsKey(var.getName())) { + String newVarName = var.getName() + ReplaceConfiguration.REPLACEMENT_VARIABLE_SUFFIX; + varsMap.put(newVarName, new Variable(newVarName, null, null, false, false)); + } + } + return new ArrayList<Variable>(varsMap.values()); + } + + protected boolean isValid() { + if (!super.isValid()) return false; + + try { + Replacer.checkSupportedReplacementPattern(searchContext.getProject(), ((ReplaceConfiguration)model.getConfig()).getOptions()); + } + catch (UnsupportedPatternException ex) { + reportMessage("unsupported.replacement.pattern.message", replaceCriteriaEdit, ex.getMessage()); + return false; + } + catch (MalformedPatternException ex) { + reportMessage("malformed.replacement.pattern.message", replaceCriteriaEdit, ex.getMessage()); + return false; + } + + return true; + } + + public void show() { + replaceCriteriaEdit.putUserData(SubstitutionShortInfoHandler.CURRENT_CONFIGURATION_KEY, model.getConfig()); + + super.show(); + } + + protected boolean isReplaceDialog() { + return true; + } + + protected void addOrReplaceSelection(final String selection) { + super.addOrReplaceSelection(selection); + addOrReplaceSelectionForEditor(selection, replaceCriteriaEdit); + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java new file mode 100644 index 000000000000..6a0d352d3284 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplaceUsageViewContext.java @@ -0,0 +1,180 @@ +package com.intellij.structuralsearch.plugin.replace.ui; + +import com.intellij.history.LocalHistory; +import com.intellij.history.LocalHistoryAction; +import com.intellij.openapi.vfs.ReadonlyStatusHandler; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.structuralsearch.SSRBundle; +import com.intellij.structuralsearch.plugin.replace.ReplacementInfo; +import com.intellij.structuralsearch.plugin.replace.impl.Replacer; +import com.intellij.structuralsearch.plugin.ui.Configuration; +import com.intellij.structuralsearch.plugin.ui.SearchCommand; +import com.intellij.structuralsearch.plugin.ui.SearchContext; +import com.intellij.structuralsearch.plugin.ui.UsageViewContext; +import com.intellij.usageView.UsageInfo; +import com.intellij.usages.Usage; +import com.intellij.usages.UsageInfo2UsageAdapter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +/** + * Created by IntelliJ IDEA. + * User: Maxim.Mossienko + * Date: Mar 9, 2005 + * Time: 4:37:08 PM + * To change this template use File | Settings | File Templates. + */ +class ReplaceUsageViewContext extends UsageViewContext { + private HashMap<Usage,ReplacementInfo> usage2ReplacementInfo; + private Replacer replacer; + + ReplaceUsageViewContext(final SearchContext context, final Configuration configuration) { + super(context,configuration); + } + + protected SearchCommand createCommand() { + ReplaceCommand command = new ReplaceCommand(mySearchContext.getProject(), this); + + usage2ReplacementInfo = new HashMap<Usage, ReplacementInfo>(); + replacer = new Replacer(mySearchContext.getProject(), ((ReplaceConfiguration)myConfiguration).getOptions()); + + return command; + } + + protected String _getPresentableText() { + return SSRBundle.message("replaceusageview.text", + getConfiguration().getMatchOptions().getSearchPattern(), + ((ReplaceConfiguration)getConfiguration()).getOptions().getReplacement() + ); + } + + public Replacer getReplacer() { + return replacer; + } + + public void addReplaceUsage(final Usage usage, final ReplacementInfo replacementInfo) { + usage2ReplacementInfo.put(usage,replacementInfo); + } + + private boolean isValid(UsageInfo2UsageAdapter info) { + final UsageInfo usageInfo = info.getUsageInfo(); + return !isExcluded(info) && usageInfo.getElement() != null && usageInfo.getElement().isValid(); + } + + @Override + protected void configureActions() { + final Runnable replaceRunnable = new Runnable() { + public void run() { + LocalHistoryAction labelAction = LocalHistory.getInstance().startAction(SSRBundle.message("structural.replace.title")); + + doReplace(); + getUsageView().close(); + + labelAction.finish(); + } + }; + + //noinspection HardCodedStringLiteral + getUsageView().addPerformOperationAction(replaceRunnable, "Replace All", null, SSRBundle.message("do.replace.all.button")); + + final Runnable replaceSelected = new Runnable() { + public void run() { + final Set<Usage> infos = getUsageView().getSelectedUsages(); + if (infos == null || infos.isEmpty()) return; + + LocalHistoryAction labelAction = LocalHistory.getInstance().startAction(SSRBundle.message("structural.replace.title")); + + for (final Usage info : infos) { + final UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter)info; + + if (isValid(usage)) { + replaceOne(usage, false); + } + } + + labelAction.finish(); + + if (getUsageView().getUsagesCount() > 0) { + for (Usage usage : getUsageView().getSortedUsages()) { + if (!isExcluded(usage)) { + getUsageView().selectUsages(new Usage[]{usage}); + return; + } + } + } + } + }; + + getUsageView().addButtonToLowerPane(replaceSelected, SSRBundle.message("replace.selected.button")); + + final Runnable previewReplacement = new Runnable() { + public void run() { + Set<Usage> selection = getUsageView().getSelectedUsages(); + + if (selection != null && !selection.isEmpty()) { + UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter)selection.iterator().next(); + + if (isValid(usage)) { + replaceOne(usage, true); + } + } + } + }; + + getUsageView().addButtonToLowerPane(previewReplacement, SSRBundle.message("preview.replacement.button")); + + super.configureActions(); + } + + private static void ensureFileWritable(final UsageInfo2UsageAdapter usage) { + final VirtualFile file = usage.getFile(); + + if (file != null && !file.isWritable()) { + ReadonlyStatusHandler.getInstance(usage.getElement().getProject()).ensureFilesWritable(file); + } + } + + private void replaceOne(UsageInfo2UsageAdapter info, boolean doConfirm) { + ReplacementInfo replacementInfo = usage2ReplacementInfo.get(info); + boolean approved; + + if (doConfirm) { + ReplacementPreviewDialog wrapper = + new ReplacementPreviewDialog(mySearchContext.getProject(), info.getUsageInfo(), replacementInfo.getReplacement()); + + wrapper.show(); + approved = wrapper.isOK(); + } + else { + approved = true; + } + + if (approved) { + ensureFileWritable(info); + getUsageView().removeUsage(info); + getReplacer().replace(replacementInfo); + + if (getUsageView().getUsagesCount() == 0) { + getUsageView().close(); + } + } + } + + private void doReplace() { + List<Usage> infos = getUsageView().getSortedUsages(); + List<ReplacementInfo> results = new ArrayList<ReplacementInfo>(infos.size()); + + for (final Usage info : infos) { + UsageInfo2UsageAdapter usage = (UsageInfo2UsageAdapter)info; + + if (isValid(usage)) { + results.add(usage2ReplacementInfo.get(usage)); + } + } + + getReplacer().replaceAll(results); + } +} diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplacementPreviewDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplacementPreviewDialog.java new file mode 100644 index 000000000000..5bec5a920b45 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/ui/ReplacementPreviewDialog.java @@ -0,0 +1,132 @@ +package com.intellij.structuralsearch.plugin.replace.ui; + +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.HighlighterLayer; +import com.intellij.openapi.editor.markup.HighlighterTargetArea; +import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Segment; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.structuralsearch.SSRBundle; +import com.intellij.structuralsearch.StructuralSearchProfile; +import com.intellij.structuralsearch.StructuralSearchUtil; +import com.intellij.structuralsearch.plugin.ui.UIUtil; +import com.intellij.usageView.UsageInfo; + +import javax.swing.*; +import java.awt.*; + +/** + * Navigates through the search results + */ +public final class ReplacementPreviewDialog extends DialogWrapper { + private final FileType myFileType; + private Editor replacement; + + private final Project project; + private RangeHighlighter hilighter; + private Editor editor; + + + public ReplacementPreviewDialog(final Project project, UsageInfo info, String replacementString) { + super(project,true); + + setTitle(SSRBundle.message("structural.replace.preview.dialog.title")); + setOKButtonText(SSRBundle.message("replace.preview.oktext")); + this.project = project; + final PsiElement element = info.getElement(); + final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element); + myFileType = virtualFile != null ? virtualFile.getFileType() : FileTypes.PLAIN_TEXT; + init(); + + Segment range = info.getSegment(); + hilight(virtualFile, range.getStartOffset(), range.getEndOffset()); + UIUtil.setContent(replacement, replacementString,0,-1,project); + + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByPsiElement(element); + if (profile != null) { + UIUtil.updateHighlighter(replacement, profile); + } + } + + private void hilight(VirtualFile file,int start, int end) { + removeHilighter(); + + editor = FileEditorManager.getInstance(project).openTextEditor( + new OpenFileDescriptor(project, file), + false + ); + hilighter = editor.getMarkupModel().addRangeHighlighter( + start, + end, + HighlighterLayer.SELECTION - 100, + EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES), + HighlighterTargetArea.EXACT_RANGE + ); + } + + private void removeHilighter() { + if (hilighter!=null && hilighter.isValid()) { + hilighter.dispose(); + hilighter = null; + editor = null; + } + } + + protected String getDimensionServiceKey() { + return "#com.intellij.strucuturalsearch.plugin.replace.ReplacementPreviewDialog"; + } + + protected JComponent createCenterPanel() { + JComponent centerPanel = new JPanel( new BorderLayout() ); + + PsiFile file = null; + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(myFileType); + if (profile != null) { + file = profile.createCodeFragment(project, "", null); + } + + if (file != null) { + final Document document = PsiDocumentManager.getInstance(project).getDocument(file); + replacement = UIUtil.createEditor(document, project, true, null); + DaemonCodeAnalyzer.getInstance(project).setHighlightingEnabled(file,false); + } else { + final EditorFactory factory = EditorFactory.getInstance(); + final Document document = factory.createDocument(""); + replacement = factory.createEditor(document, project, myFileType, false); + } + + centerPanel.add(BorderLayout.NORTH,new JLabel(SSRBundle.message("replacement.code")) ); + centerPanel.add(BorderLayout.CENTER,replacement.getComponent() ); + centerPanel.setMaximumSize(new Dimension(640,480)); + + return centerPanel; + } + + public void dispose() { + final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(replacement.getDocument()); + if (file != null) { + DaemonCodeAnalyzer.getInstance(project).setHighlightingEnabled(file, true); + } + + EditorFactory.getInstance().releaseEditor(replacement); + removeHilighter(); + + super.dispose(); + } +} + |