blob: f304a06ec96cb195f0357f11b2b59cacd9fe56b8 [file] [log] [blame]
package com.intellij.codeInsight.generation;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.MemberChooser;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.psi.PsiElement;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* @author Dmitry Batkovich
*/
public class JavaOverrideImplementMemberChooser extends MemberChooser<PsiMethodMember> {
private static final String SORT_METHODS_BY_PERCENT_DESCRIPTION = "Sort by Percent of Classes which Overrides a Method";
@NonNls public static final String PROP_COMBINED_OVERRIDE_IMPLEMENT = "OverrideImplement.combined";
@NonNls public static final String PROP_OVERRIDING_SORTED_OVERRIDE_IMPLEMENT = "OverrideImplement.overriding.sorted";
private ToggleAction mySortByOverridingAction;
private ToggleAction myMergeAction;
private final PsiMethodMember[] myAllElements;
private final PsiMethodMember[] myOnlyPrimaryElements;
private final NotNullLazyValue<PsiMethodWithOverridingPercentMember[]> myLazyElementsWithPercent;
private final boolean myToImplement;
private Project myProject;
private boolean myMerge;
private boolean mySortedByOverriding;
@Nullable
public static JavaOverrideImplementMemberChooser create(final PsiElement aClass,
final boolean toImplement,
final Collection<CandidateInfo> candidates,
final Collection<CandidateInfo> secondary) {
final Project project = aClass.getProject();
if (candidates.isEmpty() && secondary.isEmpty()) return null;
final PsiMethodMember[] onlyPrimary = convertToMethodMembers(candidates);
final LinkedHashSet<CandidateInfo> allCandidates = new LinkedHashSet<CandidateInfo>(candidates);
allCandidates.addAll(secondary);
final PsiMethodMember[] all = convertToMethodMembers(allCandidates);
final NotNullLazyValue<PsiMethodWithOverridingPercentMember[]> lazyElementsWithPercent =
new NotNullLazyValue<PsiMethodWithOverridingPercentMember[]>() {
@NotNull
@Override
protected PsiMethodWithOverridingPercentMember[] compute() {
final PsiMethodWithOverridingPercentMember[] elements =
PsiMethodWithOverridingPercentMember.calculateOverridingPercents(candidates);
Arrays.sort(elements, PsiMethodWithOverridingPercentMember.COMPARATOR);
return elements;
}
};
final boolean merge = PropertiesComponent.getInstance(project).getBoolean(PROP_COMBINED_OVERRIDE_IMPLEMENT, true);
final JavaOverrideImplementMemberChooser javaOverrideImplementMemberChooser =
new JavaOverrideImplementMemberChooser(all, onlyPrimary, lazyElementsWithPercent, project, PsiUtil.isLanguageLevel5OrHigher(aClass),
merge, toImplement, PropertiesComponent.getInstance(project)
.getBoolean(PROP_OVERRIDING_SORTED_OVERRIDE_IMPLEMENT, false));
javaOverrideImplementMemberChooser.setTitle(getChooserTitle(toImplement, merge));
javaOverrideImplementMemberChooser.setCopyJavadocVisible(true);
if (toImplement) {
if (onlyPrimary.length == 0) {
javaOverrideImplementMemberChooser.selectElements(new ClassMember[] {all[0]});
} else {
javaOverrideImplementMemberChooser.selectElements(onlyPrimary);
}
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
if (!toImplement || onlyPrimary.length == 0) {
javaOverrideImplementMemberChooser.selectElements(all);
}
javaOverrideImplementMemberChooser.close(DialogWrapper.OK_EXIT_CODE);
return javaOverrideImplementMemberChooser;
}
return javaOverrideImplementMemberChooser;
}
private JavaOverrideImplementMemberChooser(final PsiMethodMember[] allElements,
final PsiMethodMember[] onlyPrimaryElements,
final NotNullLazyValue<PsiMethodWithOverridingPercentMember[]> lazyElementsWithPercent,
final @NotNull Project project,
final boolean isInsertOverrideVisible,
final boolean merge,
final boolean toImplement,
final boolean sortedByOverriding) {
super(false, true, project, isInsertOverrideVisible, null, null);
myAllElements = allElements;
myOnlyPrimaryElements = onlyPrimaryElements;
myLazyElementsWithPercent = lazyElementsWithPercent;
myProject = project;
myMerge = merge;
myToImplement = toImplement;
mySortedByOverriding = sortedByOverriding;
resetElements(getInitialElements(allElements, onlyPrimaryElements, lazyElementsWithPercent, merge, toImplement, sortedByOverriding));
init();
}
private static PsiMethodMember[] getInitialElements(PsiMethodMember[] allElements,
PsiMethodMember[] onlyPrimaryElements,
NotNullLazyValue<PsiMethodWithOverridingPercentMember[]> lazyElementsWithPercent,
boolean merge,
boolean toImplement,
boolean sortByOverriding) {
final boolean showElementsWithPercents = sortByOverriding && !toImplement;
final PsiMethodMember[] defaultElements = toImplement || merge ? allElements : onlyPrimaryElements;
return showElementsWithPercents ? lazyElementsWithPercent.getValue() : defaultElements;
}
@Override
protected void onAlphabeticalSortingEnabled(final AnActionEvent event) {
resetElements(myToImplement || myMerge ? myAllElements : myOnlyPrimaryElements, null, true);
if (mySortByOverridingAction != null) {
mySortByOverridingAction.setSelected(event, false);
}
}
@Override
protected void doOKAction() {
super.doOKAction();
PropertiesComponent.getInstance(myProject).setValue(PROP_COMBINED_OVERRIDE_IMPLEMENT, String.valueOf(myMerge));
PropertiesComponent.getInstance(myProject).setValue(PROP_OVERRIDING_SORTED_OVERRIDE_IMPLEMENT, String.valueOf(mySortedByOverriding));
}
@Override
protected void fillToolbarActions(DefaultActionGroup group) {
super.fillToolbarActions(group);
if (myToImplement) return;
mySortByOverridingAction = new MySortByOverridingAction();
if (mySortedByOverriding) {
changeSortComparator(PsiMethodWithOverridingPercentMember.COMPARATOR);
}
group.add(mySortByOverridingAction, Constraints.FIRST);
myMergeAction = new MyMergeAction();
group.add(myMergeAction);
}
private static String getChooserTitle(final boolean toImplement, final boolean merge) {
return toImplement
? CodeInsightBundle.message("methods.to.implement.chooser.title")
: merge
? CodeInsightBundle.message("methods.to.override.implement.chooser.title")
: CodeInsightBundle.message("methods.to.override.chooser.title");
}
private static PsiMethodMember[] convertToMethodMembers(Collection<CandidateInfo> candidates) {
return ContainerUtil.map2Array(candidates, PsiMethodMember.class, new Function<CandidateInfo, PsiMethodMember>() {
@Override
public PsiMethodMember fun(final CandidateInfo s) {
return new PsiMethodMember(s);
}
});
}
private class MySortByOverridingAction extends ToggleAction {
public MySortByOverridingAction() {
super(SORT_METHODS_BY_PERCENT_DESCRIPTION, SORT_METHODS_BY_PERCENT_DESCRIPTION, AllIcons.ObjectBrowser.SortedByUsage);
registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.ALT_MASK)), myTree);
}
@Override
public boolean isSelected(final AnActionEvent e) {
return mySortedByOverriding;
}
@Override
public void setSelected(final AnActionEvent e, final boolean state) {
mySortedByOverriding = state;
if (state) {
if (myMerge) {
myMergeAction.setSelected(e, false);
}
disableAlphabeticalSorting(e);
final PsiMethodWithOverridingPercentMember[] elementsWithPercent = myLazyElementsWithPercent.getValue();
resetElements(elementsWithPercent, PsiMethodWithOverridingPercentMember.COMPARATOR, false);
}
else {
final PsiMethodMember[] elementsToRender = myMerge ? myAllElements : myOnlyPrimaryElements;
resetElementsWithDefaultComparator(elementsToRender, true);
}
}
}
private class MyMergeAction extends ToggleAction {
private MyMergeAction() {
super("Show methods to implement", "Show methods to implement", AllIcons.General.Show_to_implement);
registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK)), myTree);
final Shortcut[] shortcuts = KeymapManager.getInstance().getActiveKeymap().getShortcuts("OverrideMethods");
registerCustomShortcutSet(new CustomShortcutSet(shortcuts), myTree);
}
@Override
public boolean isSelected(AnActionEvent e) {
return myMerge;
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
myMerge = state;
if (state && mySortByOverridingAction.isSelected(e)) {
mySortByOverridingAction.setSelected(e, false);
}
resetElements(state ? myAllElements : myOnlyPrimaryElements, null, true);
setTitle(getChooserTitle(false, myMerge));
}
}
}