blob: 1e95ac69887e7b651bcc481b3897a381dfe9fe6a [file] [log] [blame]
/*
* Copyright 2000-2014 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.ide.structureView.impl.java;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.ide.util.treeView.smartTree.*;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.util.ArrayUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public class SuperTypesGrouper implements Grouper{
public static final Key<WeakReference<PsiMethod>> SUPER_METHOD_KEY = Key.create("StructureTreeBuilder.SUPER_METHOD_KEY");
@NonNls public static final String ID = "SHOW_INTERFACES";
@Override
@NotNull
public Collection<Group> group(@NotNull final AbstractTreeNode parent, @NotNull Collection<TreeElement> children) {
if (isParentGrouped(parent)) return Collections.emptyList();
Map<Group, SuperTypeGroup> groups = new THashMap<Group, SuperTypeGroup>();
for (TreeElement child : children) {
if (child instanceof PsiMethodTreeElement) {
final PsiMethodTreeElement element = (PsiMethodTreeElement)child;
PsiMethod method = ((PsiMethodTreeElement)child).getMethod();
if (element.isInherited()) {
PsiClass groupClass = method.getContainingClass();
final SuperTypeGroup group = getOrCreateGroup(groupClass, SuperTypeGroup.OwnershipType.INHERITS, groups);
group.addMethod(child);
}
else {
PsiMethod[] superMethods = method.findSuperMethods();
if (superMethods.length > 0) {
//prefer interface, if there are any
for (int i = 1; i < superMethods.length; i++) {
PsiMethod superMethod = superMethods[i];
PsiClass containingClass = superMethod.getContainingClass();
if (containingClass != null && containingClass.isInterface()) {
ArrayUtil.swap(superMethods, 0, i);
break;
}
}
PsiMethod superMethod = superMethods[0];
method.putUserData(SUPER_METHOD_KEY, new WeakReference<PsiMethod>(superMethod));
PsiClass groupClass = superMethod.getContainingClass();
boolean overrides = methodOverridesSuper(method, superMethod);
final SuperTypeGroup.OwnershipType ownershipType =
overrides ? SuperTypeGroup.OwnershipType.OVERRIDES : SuperTypeGroup.OwnershipType.IMPLEMENTS;
SuperTypeGroup group = getOrCreateGroup(groupClass, ownershipType, groups);
group.addMethod(child);
}
}
}
}
return groups.keySet();
}
private static SuperTypeGroup getOrCreateGroup(final PsiClass groupClass, final SuperTypeGroup.OwnershipType ownershipType, final Map<Group, SuperTypeGroup> groups) {
SuperTypeGroup superTypeGroup =
new SuperTypeGroup(groupClass, ownershipType);
SuperTypeGroup existing = groups.get(superTypeGroup);
if (existing == null) {
groups.put(superTypeGroup, superTypeGroup);
existing = superTypeGroup;
}
return existing;
}
private static boolean isParentGrouped(AbstractTreeNode parent) {
while (parent != null) {
if (parent.getValue() instanceof SuperTypeGroup) return true;
parent = parent.getParent();
}
return false;
}
private static boolean methodOverridesSuper(PsiMethod method, PsiMethod superMethod) {
boolean overrides = false;
if (method.hasModifierProperty(PsiModifier.ABSTRACT)){
overrides = true;
}
else if (!superMethod.hasModifierProperty(PsiModifier.ABSTRACT)){
overrides = true;
}
return overrides;
}
@Override
@NotNull
public ActionPresentation getPresentation() {
return new ActionPresentationData(IdeBundle.message("action.structureview.group.methods.by.defining.type"), null,
AllIcons.General.ImplementingMethod);
}
@Override
@NotNull
public String getName() {
return ID;
}
}