diff --git a/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java b/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java index e07920b4..e2610563 100644 --- a/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java +++ b/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java @@ -36,11 +36,11 @@ import com.intellij.debugger.SourcePosition; import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; -import com.intellij.navigation.ItemPresentationProviders; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.PsiModifier.ModifierConstant; +import com.intellij.psi.impl.ElementPresentationUtil; import com.intellij.psi.impl.InheritanceImplUtil; import com.intellij.psi.impl.PsiClassImplUtil; import com.intellij.psi.impl.PsiImplUtil; @@ -59,13 +59,14 @@ import org.jf.smalidea.psi.iface.SmaliModifierListOwner; import org.jf.smalidea.psi.leaf.SmaliClassDescriptor; import org.jf.smalidea.psi.stub.SmaliClassStub; +import org.jf.smalidea.util.IconUtils; import javax.annotation.Nonnull; import javax.swing.*; import java.util.Collection; import java.util.List; -public class SmaliClass extends SmaliStubBasedPsiElement implements PsiClass, SmaliModifierListOwner { +public class SmaliClass extends SmaliStubBasedPsiElement implements PsiClass, SmaliModifierListOwner, ItemPresentation { public SmaliClass(@NotNull SmaliClassStub stub) { super(stub, SmaliElementTypes.CLASS); } @@ -89,7 +90,7 @@ public String getName() { } @Override public ItemPresentation getPresentation() { - return ItemPresentationProviders.getItemPresentation(this); + return this; } @Nullable @Override public String getQualifiedName() { @@ -422,4 +423,23 @@ public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNul @Nullable @Override protected Icon getElementIcon(@IconFlags int flags) { return SmaliIcons.SmaliIcon; } + + @Nullable + @Override + public String getPresentableText() { + return getName(); + } + + @Nullable + @Override + public String getLocationString() { + return getPackageName(); + } + + @Nullable + @Override + public Icon getIcon(boolean unused) { + int basicClassKind = ElementPresentationUtil.getBasicClassKind(this); + return IconUtils.getElementIcon(this, ElementPresentationUtil.getClassIconOfKind(this, basicClassKind)); + } } \ No newline at end of file diff --git a/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java b/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java index a9b7d7fd..c6a9103a 100644 --- a/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java +++ b/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java @@ -32,20 +32,25 @@ package org.jf.smalidea.psi.impl; import com.intellij.lang.ASTNode; +import com.intellij.navigation.ItemPresentation; import com.intellij.psi.*; import com.intellij.psi.PsiModifier.ModifierConstant; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.PlatformIcons; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jf.smalidea.psi.SmaliElementTypes; import org.jf.smalidea.psi.iface.SmaliModifierListOwner; import org.jf.smalidea.psi.stub.SmaliFieldStub; +import org.jf.smalidea.util.IconUtils; import org.jf.smalidea.util.NameUtils; -public class SmaliField extends SmaliStubBasedPsiElement implements PsiField, SmaliModifierListOwner { +import javax.swing.*; + +public class SmaliField extends SmaliStubBasedPsiElement implements PsiField, SmaliModifierListOwner, ItemPresentation { public SmaliField(@NotNull SmaliFieldStub stub) { super(stub, SmaliElementTypes.FIELD); } @@ -79,6 +84,11 @@ public SmaliField(@NotNull ASTNode node) { return memberName; } + @Override + public ItemPresentation getPresentation() { + return this; + } + @Nullable @Override public PsiDocComment getDocComment() { return null; } @@ -175,4 +185,22 @@ public SmaliField(@NotNull ASTNode node) { } return super.getTextOffset(); } + + @Nullable + @Override + public String getPresentableText() { + return getName() + ": " + getType().getPresentableText(); + } + + @Nullable + @Override + public String getLocationString() { + return ""; + } + + @Nullable + @Override + public Icon getIcon(boolean unused) { + return IconUtils.getElementIcon(this, PlatformIcons.FIELD_ICON); + } } diff --git a/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java b/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java index 44cd9093..f90a5fa0 100644 --- a/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java +++ b/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java @@ -36,16 +36,17 @@ import com.google.common.collect.Maps; import com.intellij.debugger.SourcePosition; import com.intellij.lang.ASTNode; +import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.editor.Document; import com.intellij.psi.*; import com.intellij.psi.PsiModifier.ModifierConstant; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.util.MethodSignature; -import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.*; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.PlatformIcons; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -57,14 +58,16 @@ import org.jf.smalidea.psi.SmaliElementTypes; import org.jf.smalidea.psi.iface.SmaliModifierListOwner; import org.jf.smalidea.psi.stub.SmaliMethodStub; +import org.jf.smalidea.util.IconUtils; +import javax.swing.*; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; public class SmaliMethod extends SmaliStubBasedPsiElement - implements PsiMethod, SmaliModifierListOwner, PsiAnnotationMethod { + implements PsiMethod, SmaliModifierListOwner, PsiAnnotationMethod, ItemPresentation { public SmaliMethod(@NotNull SmaliMethodStub stub) { super(stub, SmaliElementTypes.METHOD); } @@ -90,6 +93,10 @@ public SmaliMethod(@NotNull ASTNode node) { return name; } + @Override public ItemPresentation getPresentation() { + return this; + } + @Override public boolean hasTypeParameters() { // TODO: (generics) implement this return false; @@ -372,4 +379,37 @@ public MethodAnalyzer getMethodAnalyzer() { } return null; } + + @Nullable + @Override + public String getPresentableText() { + return PsiFormatUtil.formatMethod(this, PsiSubstitutor.EMPTY, + PsiFormatUtilBase.SHOW_NAME + | PsiFormatUtilBase.SHOW_TYPE | PsiFormatUtilBase.TYPE_AFTER + | PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE); + } + + @Nullable + @Override + public String getLocationString() { + PsiMethod superMethod = findDeepestSuperMethod(); + if (superMethod != null) { + char upArrow = '\u2191'; + PsiClass containingClass = superMethod.getContainingClass(); + if (containingClass != null) { + String location = containingClass.getQualifiedName(); + return UIUtil.getLabelFont().canDisplay(upArrow) ? upArrow + location : location; + } + } + return ""; + } + + @Nullable + @Override + public Icon getIcon(boolean unused) { + return IconUtils.getElementIcon(this, hasModifierProperty(PsiModifier.ABSTRACT) + ? PlatformIcons.ABSTRACT_METHOD_ICON + : PlatformIcons.METHOD_ICON); + } } diff --git a/src/main/java/org/jf/smalidea/structureView/SmaliFileTreeModel.java b/src/main/java/org/jf/smalidea/structureView/SmaliFileTreeModel.java new file mode 100644 index 00000000..94487cb3 --- /dev/null +++ b/src/main/java/org/jf/smalidea/structureView/SmaliFileTreeModel.java @@ -0,0 +1,31 @@ +package org.jf.smalidea.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.Sorter; +import org.jetbrains.annotations.NotNull; +import org.jf.smalidea.psi.impl.SmaliFile; + +public class SmaliFileTreeModel extends StructureViewModelBase implements + StructureViewModel.ElementInfoProvider { + public SmaliFileTreeModel(SmaliFile psiFile) { + super(psiFile, new SmaliStructureViewElement(psiFile)); + } + + @NotNull + public Sorter[] getSorters() { + return new Sorter[] { + Sorter.ALPHA_SORTER}; + } + + @Override + public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { + return false; + } + + @Override + public boolean isAlwaysLeaf(StructureViewTreeElement element) { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/org/jf/smalidea/structureView/SmaliStructureViewBuilderFactory.java b/src/main/java/org/jf/smalidea/structureView/SmaliStructureViewBuilderFactory.java new file mode 100644 index 00000000..34a8bc7e --- /dev/null +++ b/src/main/java/org/jf/smalidea/structureView/SmaliStructureViewBuilderFactory.java @@ -0,0 +1,33 @@ +package org.jf.smalidea.structureView; + +import com.intellij.ide.structureView.StructureViewBuilder; +import com.intellij.ide.structureView.StructureViewModel; +import com.intellij.ide.structureView.TreeBasedStructureViewBuilder; +import com.intellij.lang.PsiStructureViewFactory; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jf.smalidea.psi.impl.SmaliFile; + +public class SmaliStructureViewBuilderFactory implements PsiStructureViewFactory { + @Nullable + @Override + public StructureViewBuilder getStructureViewBuilder(@NotNull final PsiFile psiFile) { + if (!(psiFile instanceof SmaliFile)) { + return null; + } + return new TreeBasedStructureViewBuilder() { + @Override + @NotNull + public StructureViewModel createStructureViewModel(@Nullable Editor editor) { + return new SmaliFileTreeModel((SmaliFile) psiFile); + } + + @Override + public boolean isRootNodeShown() { + return false; + } + }; + } +} diff --git a/src/main/java/org/jf/smalidea/structureView/SmaliStructureViewElement.java b/src/main/java/org/jf/smalidea/structureView/SmaliStructureViewElement.java new file mode 100644 index 00000000..7ee2b5ca --- /dev/null +++ b/src/main/java/org/jf/smalidea/structureView/SmaliStructureViewElement.java @@ -0,0 +1,87 @@ +package org.jf.smalidea.structureView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.structureView.StructureViewTreeElement; +import com.intellij.ide.util.treeView.smartTree.SortableTreeElement; +import com.intellij.ide.util.treeView.smartTree.TreeElement; +import com.intellij.navigation.ItemPresentation; +import com.intellij.psi.NavigatablePsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiMethod; +import org.jetbrains.annotations.NotNull; +import org.jf.smalidea.psi.impl.SmaliClass; +import org.jf.smalidea.psi.impl.SmaliFile; + +import java.util.ArrayList; +import java.util.List; + +public class SmaliStructureViewElement implements StructureViewTreeElement, SortableTreeElement { + private final NavigatablePsiElement element; + + public SmaliStructureViewElement(NavigatablePsiElement element) { + this.element = element; + } + + @Override + public Object getValue() { + return element; + } + + @Override + public void navigate(boolean requestFocus) { + element.navigate(requestFocus); + } + + @Override + public boolean canNavigate() { + return element.canNavigate(); + } + + @Override + public boolean canNavigateToSource() { + return element.canNavigateToSource(); + } + + @NotNull + @Override + public String getAlphaSortKey() { + String name = element.getName(); + return name != null ? name : ""; + } + + @NotNull + @Override + public ItemPresentation getPresentation() { + ItemPresentation presentation = element.getPresentation(); + return presentation != null ? presentation : new PresentationData(); + } + + @NotNull + @Override + public TreeElement[] getChildren() { + if (element instanceof SmaliFile) { + SmaliFile smaliFile = (SmaliFile) element; + SmaliClass[] classes = smaliFile.getClasses(); + TreeElement[] treeElements = new TreeElement[classes.length]; + for (int i = 0; i < classes.length; i++) { + treeElements[i] = new SmaliStructureViewElement(classes[i]); + } + return treeElements; + } else if (element instanceof SmaliClass) { + SmaliClass smaliClass = (SmaliClass) element; + PsiField[] fields = smaliClass.getFields(); + PsiMethod[] methods = smaliClass.getMethods(); + + List treeElements = new ArrayList<>(fields.length + methods.length); + for (PsiField field : fields) { + treeElements.add(new SmaliStructureViewElement(field)); + } + for (PsiMethod method : methods) { + treeElements.add(new SmaliStructureViewElement(method)); + } + return treeElements.toArray(new TreeElement[0]); + } else { + return EMPTY_ARRAY; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jf/smalidea/util/IconUtils.java b/src/main/java/org/jf/smalidea/util/IconUtils.java new file mode 100644 index 00000000..5a24bd46 --- /dev/null +++ b/src/main/java/org/jf/smalidea/util/IconUtils.java @@ -0,0 +1,34 @@ +package org.jf.smalidea.util; + +import com.intellij.ui.RowIcon; +import com.intellij.util.PlatformIcons; +import org.jf.dexlib2.AccessFlags; +import org.jf.smalidea.psi.iface.SmaliModifierListOwner; +import org.jf.smalidea.psi.impl.SmaliModifierList; + +import javax.swing.*; + +public class IconUtils { + public static Icon getElementIcon(SmaliModifierListOwner modifierListOwner, Icon leftIcon) { + SmaliModifierList modifierList = modifierListOwner.getModifierList(); + int accessFlags = modifierList == null ? 0 : modifierList.getAccessFlags(); + Icon rightIcon = IconUtils.getAccessibilityIcon(accessFlags); + if (rightIcon != null) { + return new RowIcon(leftIcon, rightIcon); + } else { + return leftIcon; + } + } + + public static Icon getAccessibilityIcon(int accessFlags) { + if (AccessFlags.PUBLIC.isSet(accessFlags)) { + return PlatformIcons.PUBLIC_ICON; + } else if (AccessFlags.PRIVATE.isSet(accessFlags)) { + return PlatformIcons.PRIVATE_ICON; + } else if (AccessFlags.PROTECTED.isSet(accessFlags)) { + return PlatformIcons.PROTECTED_ICON; + } else { + return PlatformIcons.PACKAGE_LOCAL_ICON; + } + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 8eb674cf..6ec486dc 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -30,6 +30,8 @@ +