mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Show inherited members in structure view (PY-3936)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user