| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.refactoring.introduce.inplace; |
| |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.editor.colors.EditorColors; |
| import com.intellij.openapi.editor.colors.EditorColorsManager; |
| import com.intellij.openapi.editor.markup.*; |
| import com.intellij.openapi.ui.popup.JBPopupAdapter; |
| import com.intellij.openapi.ui.popup.JBPopupFactory; |
| import com.intellij.openapi.ui.popup.LightweightWindowEvent; |
| import com.intellij.openapi.util.Pass; |
| import com.intellij.openapi.util.TextRange; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.ui.components.JBList; |
| import com.intellij.util.containers.ContainerUtil; |
| |
| import javax.swing.*; |
| import javax.swing.event.ListSelectionEvent; |
| import javax.swing.event.ListSelectionListener; |
| import java.awt.*; |
| import java.text.MessageFormat; |
| import java.util.*; |
| import java.util.List; |
| |
| /** |
| * User: anna |
| * Date: 10/14/10 |
| */ |
| // Please do not make this class concrete<PsiElement>. |
| // This prevents languages with polyadic expressions or sequences |
| // from reusing it, use simpleChooser instead. |
| public abstract class OccurrencesChooser<T> { |
| public enum ReplaceChoice { |
| NO("Replace this occurrence only"), NO_WRITE("Replace all occurrences but write"), ALL("Replace all {0} occurrences"); |
| |
| private final String myDescription; |
| |
| ReplaceChoice(String description) { |
| myDescription = description; |
| } |
| |
| public String getDescription() { |
| return myDescription; |
| } |
| } |
| |
| public static <T extends PsiElement> OccurrencesChooser<T> simpleChooser(Editor editor) { |
| return new OccurrencesChooser<T>(editor) { |
| @Override |
| protected TextRange getOccurrenceRange(T occurrence) { |
| return occurrence.getTextRange(); |
| } |
| }; |
| } |
| |
| private final Set<RangeHighlighter> myRangeHighlighters = new HashSet<RangeHighlighter>(); |
| private final Editor myEditor; |
| private final TextAttributes myAttributes; |
| |
| public OccurrencesChooser(Editor editor) { |
| myEditor = editor; |
| myAttributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); |
| } |
| |
| public void showChooser(final T selectedOccurrence, final List<T> allOccurrences, final Pass<ReplaceChoice> callback) { |
| if (allOccurrences.size() == 1) { |
| callback.pass(ReplaceChoice.ALL); |
| } |
| else { |
| Map<ReplaceChoice, List<T>> occurrencesMap = ContainerUtil.newLinkedHashMap(); |
| occurrencesMap.put(ReplaceChoice.NO, Collections.singletonList(selectedOccurrence)); |
| occurrencesMap.put(ReplaceChoice.ALL, allOccurrences); |
| showChooser(callback, occurrencesMap); |
| } |
| } |
| |
| public void showChooser(final Pass<ReplaceChoice> callback, final Map<ReplaceChoice, List<T>> occurrencesMap) { |
| if (occurrencesMap.size() == 1) { |
| callback.pass(occurrencesMap.keySet().iterator().next()); |
| return; |
| } |
| final DefaultListModel model = new DefaultListModel(); |
| for (ReplaceChoice choice : occurrencesMap.keySet()) { |
| model.addElement(choice); |
| } |
| final JList list = new JBList(model); |
| list.setCellRenderer(new DefaultListCellRenderer() { |
| @Override |
| public Component getListCellRendererComponent(final JList list, |
| final Object value, |
| final int index, |
| final boolean isSelected, |
| final boolean cellHasFocus) { |
| final Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); |
| final ReplaceChoice choices = (ReplaceChoice)value; |
| if (choices != null) { |
| String text = choices.getDescription(); |
| if (choices == ReplaceChoice.ALL) { |
| text = MessageFormat.format(text, occurrencesMap.get(choices).size()); |
| } |
| setText(text); |
| } |
| return rendererComponent; |
| } |
| }); |
| list.addListSelectionListener(new ListSelectionListener() { |
| @Override |
| public void valueChanged(final ListSelectionEvent e) { |
| final ReplaceChoice value = (ReplaceChoice)list.getSelectedValue(); |
| if (value == null) return; |
| dropHighlighters(); |
| final MarkupModel markupModel = myEditor.getMarkupModel(); |
| final List<T> occurrenceList = occurrencesMap.get(value); |
| for (T occurrence : occurrenceList) { |
| final TextRange textRange = getOccurrenceRange(occurrence); |
| final RangeHighlighter rangeHighlighter = markupModel.addRangeHighlighter( |
| textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.SELECTION - 1, myAttributes, |
| HighlighterTargetArea.EXACT_RANGE); |
| myRangeHighlighters.add(rangeHighlighter); |
| } |
| } |
| }); |
| |
| JBPopupFactory.getInstance().createListPopupBuilder(list) |
| .setTitle("Multiple occurrences found") |
| .setMovable(false) |
| .setResizable(false) |
| .setRequestFocus(true) |
| .setItemChoosenCallback(new Runnable() { |
| @Override |
| public void run() { |
| callback.pass((ReplaceChoice)list.getSelectedValue()); |
| } |
| }) |
| .addListener(new JBPopupAdapter() { |
| @Override |
| public void onClosed(LightweightWindowEvent event) { |
| dropHighlighters(); |
| } |
| }) |
| .createPopup().showInBestPositionFor(myEditor); |
| } |
| |
| protected abstract TextRange getOccurrenceRange(T occurrence); |
| |
| private void dropHighlighters() { |
| for (RangeHighlighter highlight : myRangeHighlighters) { |
| highlight.dispose(); |
| } |
| myRangeHighlighters.clear(); |
| } |
| } |