Show inherited members in structure view (PY-3936)

This commit is contained in:
Andrey Vlasovskikh
2011-07-05 21:32:12 +04:00
parent 5aa0bfa0c6
commit 46a358dc15
5 changed files with 164 additions and 45 deletions
@@ -0,0 +1,50 @@
package com.jetbrains.python.structureView;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
import com.intellij.ide.util.treeView.smartTree.Filter;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.openapi.util.IconLoader;
import com.jetbrains.python.psi.PyElement;
import org.jetbrains.annotations.NotNull;
/**
* @author vlan
*/
public class PyInheritedMembersFilter implements Filter {
private static final String ID = "SHOW_INHERITED";
@Override
public boolean isReverted() {
return true;
}
@Override
public boolean isVisible(TreeElement treeNode) {
if (treeNode instanceof PyStructureViewElement) {
final PyStructureViewElement sve = (PyStructureViewElement)treeNode;
return !sve.isInherited();
}
return true;
}
@NotNull
@Override
public String getName() {
return ID;
}
@Override
public String toString() {
return getName();
}
@NotNull
@Override
public ActionPresentation getPresentation() {
return new ActionPresentationData(IdeBundle.message("action.structureview.show.inherited"),
null,
IconLoader.getIcon("/hierarchy/supertypes.png"));
}
}
@@ -2,18 +2,17 @@ package com.jetbrains.python.structureView;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.LayeredIcon;
import com.intellij.util.Function;
import com.intellij.util.PlatformIcons;
import com.jetbrains.python.PyIcons;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.ParamHelper;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -39,20 +38,26 @@ public class PyStructureViewElement implements StructureViewTreeElement {
private PyElement myElement;
private Visibility myVisibility;
private Icon myIcon;
private boolean myInherited;
public PyStructureViewElement(PyElement element, Visibility vis) {
public PyStructureViewElement(PyElement element, Visibility vis, boolean inherited) {
myElement = element;
myVisibility = vis;
myInherited = inherited;
}
public PyStructureViewElement(PyElement element) {
this(element, Visibility.NORMAL);
this(element, Visibility.NORMAL, false);
}
public PyElement getValue() {
return myElement;
}
public boolean isInherited() {
return myInherited;
}
public void navigate(boolean requestFocus) {
myElement.navigate(requestFocus);
}
@@ -69,46 +74,65 @@ public class PyStructureViewElement implements StructureViewTreeElement {
myIcon = icon;
}
@Override
public boolean equals(Object o) {
if (o instanceof StructureViewTreeElement) {
final Object value = ((StructureViewTreeElement)o).getValue();
final String name = myElement.getName();
if (value instanceof PyElement && name != null) {
return name.equals(((PyElement)value).getName());
}
}
return false;
}
@Override
public int hashCode() {
final String name = myElement.getName();
return name != null ? name.hashCode() : 0;
}
public StructureViewTreeElement[] getChildren() {
final Set<PyElement> childrenElements = new LinkedHashSet<PyElement>();
myElement.acceptChildren(new PyElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof PyClass || element instanceof PyFunction ||
(!(myElement instanceof PyClass) && isWorthyItem(element))) {
childrenElements.add((PyElement)element);
}
else {
element.acceptChildren(this);
}
}
});
final Collection<StructureViewTreeElement> children = new ArrayList<StructureViewTreeElement>();
for (PyElement element : childrenElements) {
final Visibility vis;
if (PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) {
// whatever is defined inside a def, is hidden
vis = Visibility.INVISIBLE;
}
else {
vis = getVisibilityByName(element.getName());
}
final PyStructureViewElement e = new PyStructureViewElement(element, vis);
children.add(e);
if (element instanceof PyClass && element.isValid()) {
PyClass the_exception = PyBuiltinCache.getInstance(element).getClass("Exception");
final PyClass cls = (PyClass)element;
for (PyClass anc : cls.iterateAncestorClasses()) {
if (anc == the_exception) {
e.setIcon(PlatformIcons.EXCEPTION_CLASS_ICON);
break;
}
final Collection<StructureViewTreeElement> children = new LinkedHashSet<StructureViewTreeElement>();
for (PyElement e : getElementChildren(myElement)) {
children.add(new PyStructureViewElement(e, getElementVisibility(e), false));
}
if (myElement instanceof PyClass) {
for (PyClass c : ((PyClass)myElement).iterateAncestorClasses()) {
for (PyElement e: getElementChildren(c)) {
children.add(new PyStructureViewElement(e, getElementVisibility(e), true));
}
}
}
return children.toArray(new StructureViewTreeElement[children.size()]);
}
private static Visibility getElementVisibility(PyElement element) {
if (!(element instanceof PyTargetExpression) && PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) {
return Visibility.INVISIBLE;
}
else {
return getVisibilityByName(element.getName());
}
}
private static Collection<PyElement> getElementChildren(final PyElement element) {
final Collection<PyElement> children = new ArrayList<PyElement>();
element.acceptChildren(new PyElementVisitor() {
@Override
public void visitElement(PsiElement e) {
if (e instanceof PyClass || e instanceof PyFunction ||
(!(element instanceof PyClass) && isWorthyItem(e))) {
children.add((PyElement)e);
}
else {
e.acceptChildren(this);
}
}
});
final Collection<PyTargetExpression> attrs = new ArrayList<PyTargetExpression>();
if (myElement instanceof PyClass) {
final PyClass c = (PyClass)myElement;
if (element instanceof PyClass) {
final PyClass c = (PyClass)element;
final Comparator<PyTargetExpression> comparator = new Comparator<PyTargetExpression>() {
@Override
public int compare(PyTargetExpression e1, PyTargetExpression e2) {
@@ -126,10 +150,10 @@ public class PyStructureViewElement implements StructureViewTreeElement {
}
for (PyTargetExpression e : attrs) {
if (e.isValid()) {
children.add(new PyStructureViewElement(e, getVisibilityByName(e.getName())));
children.add(e);
}
}
return children.toArray(new StructureViewTreeElement[children.size()]);
return children;
}
private static Visibility getVisibilityByName(@Nullable String name) {
@@ -199,6 +223,9 @@ public class PyStructureViewElement implements StructureViewTreeElement {
@Nullable
public TextAttributesKey getTextAttributesKey() {
if (isInherited()) {
return CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES;
}
return null;
}
@@ -3,6 +3,7 @@ package com.jetbrains.python.structureView;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.StructureViewModelBase;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.util.treeView.smartTree.Filter;
import com.intellij.ide.util.treeView.smartTree.Sorter;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.psi.*;
@@ -34,6 +35,14 @@ public class PyStructureViewModel extends StructureViewModelBase implements Stru
return element instanceof PyClass;
}
@NotNull
@Override
public Filter[] getFilters() {
return new Filter[] {
new PyInheritedMembersFilter(),
};
}
@Override
public boolean isAutoExpand(StructureViewTreeElement element) {
return element.getValue() instanceof PsiFile;
@@ -0,0 +1,6 @@
class C(object):
def f(self, x):
self.x = x
def __str__(self):
return self.x
@@ -24,10 +24,12 @@ public class PyStructureViewTest extends PyLightFixtureTestCase {
" D1(C)\n" +
" D2(C)\n" +
" D3(lib1.C)\n" +
" D4(foo.bar.C)\n");
" D4(foo.bar.C)\n",
false);
}
public void testAttributes() { // PY-3371
// PY-3371
public void testAttributes() {
myFixture.configureByFile(TEST_DIRECTORY + "attributes.py");
doTest("-attributes.py\n" +
" -B(object)\n" +
@@ -48,13 +50,38 @@ public class PyStructureViewTest extends PyLightFixtureTestCase {
" i3\n" +
" i4\n" +
" i5\n" +
" g2\n");
" g2\n",
false);
}
private void doTest(final String expected) {
// PY-3936
public void testInherited() {
myFixture.configureByFile(TEST_DIRECTORY + "inherited.py");
doTest("-inherited.py\n" +
" -C(object)\n" +
" f(self, x)\n" +
" __str__(self)\n" +
" x\n" +
" __delattr__(self, name)\n" +
" __getattribute__(self, name)\n" +
" __hash__(self)\n" +
" __init__(self)\n" +
" __new__(cls, *more)\n" +
" __reduce_ex__(self, *args, **kwargs)\n" +
" __reduce__(self, *args, **kwargs)\n" +
" __repr__(self)\n" +
" __setattr__(self, name, value)\n" +
" __class__\n" +
" __dict__\n" +
" __doc__\n",
true);
}
private void doTest(final String expected, final boolean inherited) {
myFixture.testStructureView(new Consumer<StructureViewComponent>() {
@Override
public void consume(StructureViewComponent component) {
component.setActionActive("SHOW_INHERITED", !inherited);
assertTreeEqual(component.getTree(), expected);
}
});