gui: show resources
This commit is contained in:
@@ -4,6 +4,7 @@ import jadx.api.IJadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.JavaPackage;
|
||||
import jadx.api.ResourceFile;
|
||||
import jadx.core.utils.exceptions.DecodeException;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
@@ -42,7 +43,6 @@ public class JadxWrapper {
|
||||
public void run() {
|
||||
try {
|
||||
decompiler.setOutputDir(dir);
|
||||
decompiler.parseAndSaveXML();
|
||||
ThreadPoolExecutor ex = (ThreadPoolExecutor) decompiler.getSaveExecutor();
|
||||
ex.shutdown();
|
||||
while (ex.isTerminating()) {
|
||||
@@ -69,6 +69,10 @@ public class JadxWrapper {
|
||||
return decompiler.getPackages();
|
||||
}
|
||||
|
||||
public List<ResourceFile> getResources() {
|
||||
return decompiler.getResources();
|
||||
}
|
||||
|
||||
public File getOpenFile() {
|
||||
return openFile;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import jadx.gui.utils.Utils;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
|
||||
public class JClass extends JNode {
|
||||
private static final long serialVersionUID = -1239986875244097177L;
|
||||
|
||||
@@ -68,10 +70,15 @@ public class JClass extends JNode {
|
||||
}
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
public String getContent() {
|
||||
return cls.getCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSyntaxName() {
|
||||
return SyntaxConstants.SYNTAX_STYLE_JAVA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
AccessInfo accessInfo = cls.getAccessInfo();
|
||||
@@ -118,6 +125,11 @@ public class JClass extends JNode {
|
||||
return cls.getDecompiledLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSourceLine(int line) {
|
||||
return cls.getSourceLine(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return cls.hashCode();
|
||||
|
||||
@@ -9,6 +9,8 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
|
||||
public abstract class JNode extends DefaultMutableTreeNode {
|
||||
public static JNode makeFrom(JavaNode node) {
|
||||
if (node instanceof JavaClass) {
|
||||
@@ -38,7 +40,21 @@ public abstract class JNode extends DefaultMutableTreeNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract int getLine();
|
||||
public String getContent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getSyntaxName() {
|
||||
return SyntaxConstants.SYNTAX_STYLE_NONE;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Integer getSourceLine(int line) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract Icon getIcon();
|
||||
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
package jadx.gui.treemodel;
|
||||
|
||||
import jadx.api.ResourceFile;
|
||||
import jadx.api.ResourceType;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.gui.utils.OverlayIcon;
|
||||
import jadx.gui.utils.Utils;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
|
||||
public class JResource extends JNode implements Comparable<JResource> {
|
||||
private static final long serialVersionUID = -201018424302612434L;
|
||||
|
||||
private static final ImageIcon ROOT_ICON = Utils.openIcon("cf_obj");
|
||||
private static final ImageIcon FOLDER_ICON = Utils.openIcon("folder");
|
||||
private static final ImageIcon FILE_ICON = Utils.openIcon("file_obj");
|
||||
private static final ImageIcon MANIFEST_ICON = Utils.openIcon("template_obj");
|
||||
private static final ImageIcon JAVA_ICON = Utils.openIcon("java_ovr");
|
||||
private static final ImageIcon ERROR_ICON = Utils.openIcon("error_co");
|
||||
|
||||
public static enum JResType {
|
||||
ROOT,
|
||||
DIR,
|
||||
FILE
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final List<JResource> files = new ArrayList<JResource>(1);
|
||||
private final JResType type;
|
||||
private final ResourceFile resFile;
|
||||
|
||||
private boolean loaded;
|
||||
private String content;
|
||||
private Map<Integer, Integer> lineMapping;
|
||||
|
||||
public JResource(ResourceFile resFile, String name, JResType type) {
|
||||
this.resFile = resFile;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public final void update() {
|
||||
removeAllChildren();
|
||||
for (JResource res : files) {
|
||||
res.update();
|
||||
add(res);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<JResource> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
if (!loaded && resFile != null && type == JResType.FILE) {
|
||||
loaded = true;
|
||||
if (isSupportedForView(resFile.getType())) {
|
||||
CodeWriter cw = resFile.getContent();
|
||||
if (cw != null) {
|
||||
lineMapping = cw.getLineMapping();
|
||||
content = cw.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSourceLine(int line) {
|
||||
if (lineMapping == null) {
|
||||
return null;
|
||||
}
|
||||
return lineMapping.get(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSyntaxName() {
|
||||
switch (resFile.getType()) {
|
||||
case CODE:
|
||||
return super.getSyntaxName();
|
||||
case MANIFEST:
|
||||
case XML:
|
||||
return SyntaxConstants.SYNTAX_STYLE_XML;
|
||||
}
|
||||
String syntax = getSyntaxByExtension(resFile.getName());
|
||||
if (syntax != null) {
|
||||
return syntax;
|
||||
}
|
||||
return super.getSyntaxName();
|
||||
}
|
||||
|
||||
private String getSyntaxByExtension(String name) {
|
||||
int dot = name.lastIndexOf('.');
|
||||
if (dot == -1) {
|
||||
return null;
|
||||
}
|
||||
String ext = name.substring(dot + 1);
|
||||
if (ext.equals("js")) {
|
||||
return SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT;
|
||||
}
|
||||
if (ext.equals("css")) {
|
||||
return SyntaxConstants.SYNTAX_STYLE_CSS;
|
||||
}
|
||||
if (ext.equals("html")) {
|
||||
return SyntaxConstants.SYNTAX_STYLE_HTML;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
switch (type) {
|
||||
case ROOT:
|
||||
return ROOT_ICON;
|
||||
case DIR:
|
||||
return FOLDER_ICON;
|
||||
|
||||
case FILE:
|
||||
ResourceType resType = resFile.getType();
|
||||
if (resType == ResourceType.MANIFEST) {
|
||||
return MANIFEST_ICON;
|
||||
}
|
||||
if (resType == ResourceType.CODE) {
|
||||
return new OverlayIcon(FILE_ICON, ERROR_ICON, JAVA_ICON);
|
||||
}
|
||||
if (!isSupportedForView(resType)) {
|
||||
return new OverlayIcon(FILE_ICON, ERROR_ICON);
|
||||
}
|
||||
return FILE_ICON;
|
||||
}
|
||||
return FILE_ICON;
|
||||
}
|
||||
|
||||
private boolean isSupportedForView(ResourceType type) {
|
||||
switch (type) {
|
||||
case CODE:
|
||||
case XML:
|
||||
case ARSC:
|
||||
case FONT:
|
||||
case IMG:
|
||||
case LIB:
|
||||
return false;
|
||||
|
||||
case MANIFEST:
|
||||
case UNKNOWN:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(JResource o) {
|
||||
return name.compareTo(o.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
return name.equals(((JResource) o).name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +1,17 @@
|
||||
package jadx.gui.treemodel;
|
||||
|
||||
import jadx.api.JavaPackage;
|
||||
import jadx.api.ResourceFile;
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.treemodel.JResource.JResType;
|
||||
import jadx.gui.utils.Utils;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class JRoot extends JNode {
|
||||
private static final long serialVersionUID = 8888495789773527342L;
|
||||
@@ -33,102 +29,53 @@ public class JRoot extends JNode {
|
||||
|
||||
public final void update() {
|
||||
removeAllChildren();
|
||||
if (flatPackages) {
|
||||
for (JavaPackage pkg : wrapper.getPackages()) {
|
||||
add(new JPackage(pkg));
|
||||
}
|
||||
} else {
|
||||
// build packages hierarchy
|
||||
List<JPackage> rootPkgs = getHierarchyPackages(wrapper.getPackages());
|
||||
for (JPackage jPackage : rootPkgs) {
|
||||
jPackage.update();
|
||||
add(jPackage);
|
||||
}
|
||||
add(new JSources(this, wrapper));
|
||||
|
||||
List<JResource> resList = getHierarchyResources(wrapper.getResources());
|
||||
for (JResource jRes : resList) {
|
||||
jRes.update();
|
||||
add(jRes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert packages list to hierarchical packages representation
|
||||
*
|
||||
* @param packages input packages list
|
||||
* @return root packages
|
||||
*/
|
||||
List<JPackage> getHierarchyPackages(List<JavaPackage> packages) {
|
||||
Map<String, JPackage> pkgMap = new HashMap<String, JPackage>();
|
||||
for (JavaPackage pkg : packages) {
|
||||
addPackage(pkgMap, new JPackage(pkg));
|
||||
private List<JResource> getHierarchyResources(List<ResourceFile> resources) {
|
||||
if (resources.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// merge packages without classes
|
||||
boolean repeat;
|
||||
do {
|
||||
repeat = false;
|
||||
for (JPackage pkg : pkgMap.values()) {
|
||||
if (pkg.getInnerPackages().size() == 1 && pkg.getClasses().isEmpty()) {
|
||||
JPackage innerPkg = pkg.getInnerPackages().get(0);
|
||||
pkg.getInnerPackages().clear();
|
||||
pkg.getInnerPackages().addAll(innerPkg.getInnerPackages());
|
||||
pkg.getClasses().addAll(innerPkg.getClasses());
|
||||
pkg.setName(pkg.getName() + "." + innerPkg.getName());
|
||||
|
||||
innerPkg.getInnerPackages().clear();
|
||||
innerPkg.getClasses().clear();
|
||||
|
||||
repeat = true;
|
||||
break;
|
||||
JResource root = new JResource(null, "Resources", JResType.ROOT);
|
||||
String splitPathStr = Pattern.quote(File.separator);
|
||||
for (ResourceFile rf : resources) {
|
||||
String[] parts = new File(rf.getName()).getPath().split(splitPathStr);
|
||||
JResource curRf = root;
|
||||
int count = parts.length;
|
||||
for (int i = 0; i < count; i++) {
|
||||
String name = parts[i];
|
||||
JResource subRF = getResourceByName(curRf, name);
|
||||
if (subRF == null) {
|
||||
subRF = new JResource(rf, name, i != count - 1 ? JResType.DIR : JResType.FILE);
|
||||
curRf.getFiles().add(subRF);
|
||||
}
|
||||
}
|
||||
} while (repeat);
|
||||
|
||||
// remove empty packages
|
||||
for (Iterator<Map.Entry<String, JPackage>> it = pkgMap.entrySet().iterator(); it.hasNext(); ) {
|
||||
JPackage pkg = it.next().getValue();
|
||||
if (pkg.getInnerPackages().isEmpty() && pkg.getClasses().isEmpty()) {
|
||||
it.remove();
|
||||
curRf = subRF;
|
||||
}
|
||||
}
|
||||
// use identity set for collect inner packages
|
||||
Set<JPackage> innerPackages = Collections.newSetFromMap(new IdentityHashMap<JPackage, Boolean>());
|
||||
for (JPackage pkg : pkgMap.values()) {
|
||||
innerPackages.addAll(pkg.getInnerPackages());
|
||||
}
|
||||
// find root packages
|
||||
List<JPackage> rootPkgs = new ArrayList<JPackage>();
|
||||
for (JPackage pkg : pkgMap.values()) {
|
||||
if (!innerPackages.contains(pkg)) {
|
||||
rootPkgs.add(pkg);
|
||||
}
|
||||
}
|
||||
Collections.sort(rootPkgs);
|
||||
return rootPkgs;
|
||||
return Collections.singletonList(root);
|
||||
}
|
||||
|
||||
private void addPackage(Map<String, JPackage> pkgs, JPackage pkg) {
|
||||
String pkgName = pkg.getName();
|
||||
JPackage replaced = pkgs.put(pkgName, pkg);
|
||||
if (replaced != null) {
|
||||
pkg.getInnerPackages().addAll(replaced.getInnerPackages());
|
||||
pkg.getClasses().addAll(replaced.getClasses());
|
||||
}
|
||||
int dot = pkgName.lastIndexOf('.');
|
||||
if (dot > 0) {
|
||||
String prevPart = pkgName.substring(0, dot);
|
||||
String shortName = pkgName.substring(dot + 1);
|
||||
pkg.setName(shortName);
|
||||
JPackage prevPkg = pkgs.get(prevPart);
|
||||
if (prevPkg == null) {
|
||||
prevPkg = new JPackage(prevPart);
|
||||
addPackage(pkgs, prevPkg);
|
||||
private JResource getResourceByName(JResource rf, String name) {
|
||||
for (JResource sub : rf.getFiles()) {
|
||||
if (sub.getName().equals(name)) {
|
||||
return sub;
|
||||
}
|
||||
prevPkg.getInnerPackages().add(pkg);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public JClass searchClassInTree(JClass node) {
|
||||
public JNode searchClassInTree(JNode node) {
|
||||
Enumeration en = this.breadthFirstEnumeration();
|
||||
while (en.hasMoreElements()) {
|
||||
Object obj = en.nextElement();
|
||||
if (node.equals(obj)) {
|
||||
return (JClass) obj;
|
||||
return (JNode) obj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package jadx.gui.treemodel;
|
||||
|
||||
import jadx.api.JavaPackage;
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.utils.Utils;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class JSources extends JNode {
|
||||
private static final long serialVersionUID = 8962924556824862801L;
|
||||
|
||||
private static final ImageIcon ROOT_ICON = Utils.openIcon("packagefolder_obj");
|
||||
|
||||
private final JadxWrapper wrapper;
|
||||
private final boolean flatPackages;
|
||||
|
||||
public JSources(JRoot jRoot, JadxWrapper wrapper) {
|
||||
this.flatPackages = jRoot.isFlatPackages();
|
||||
this.wrapper = wrapper;
|
||||
update();
|
||||
}
|
||||
|
||||
public final void update() {
|
||||
removeAllChildren();
|
||||
if (flatPackages) {
|
||||
for (JavaPackage pkg : wrapper.getPackages()) {
|
||||
add(new JPackage(pkg));
|
||||
}
|
||||
} else {
|
||||
// build packages hierarchy
|
||||
List<JPackage> rootPkgs = getHierarchyPackages(wrapper.getPackages());
|
||||
for (JPackage jPackage : rootPkgs) {
|
||||
jPackage.update();
|
||||
add(jPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert packages list to hierarchical packages representation
|
||||
*
|
||||
* @param packages input packages list
|
||||
* @return root packages
|
||||
*/
|
||||
List<JPackage> getHierarchyPackages(List<JavaPackage> packages) {
|
||||
Map<String, JPackage> pkgMap = new HashMap<String, JPackage>();
|
||||
for (JavaPackage pkg : packages) {
|
||||
addPackage(pkgMap, new JPackage(pkg));
|
||||
}
|
||||
// merge packages without classes
|
||||
boolean repeat;
|
||||
do {
|
||||
repeat = false;
|
||||
for (JPackage pkg : pkgMap.values()) {
|
||||
if (pkg.getInnerPackages().size() == 1 && pkg.getClasses().isEmpty()) {
|
||||
JPackage innerPkg = pkg.getInnerPackages().get(0);
|
||||
pkg.getInnerPackages().clear();
|
||||
pkg.getInnerPackages().addAll(innerPkg.getInnerPackages());
|
||||
pkg.getClasses().addAll(innerPkg.getClasses());
|
||||
pkg.setName(pkg.getName() + "." + innerPkg.getName());
|
||||
|
||||
innerPkg.getInnerPackages().clear();
|
||||
innerPkg.getClasses().clear();
|
||||
|
||||
repeat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (repeat);
|
||||
|
||||
// remove empty packages
|
||||
for (Iterator<Map.Entry<String, JPackage>> it = pkgMap.entrySet().iterator(); it.hasNext(); ) {
|
||||
JPackage pkg = it.next().getValue();
|
||||
if (pkg.getInnerPackages().isEmpty() && pkg.getClasses().isEmpty()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
// use identity set for collect inner packages
|
||||
Set<JPackage> innerPackages = Collections.newSetFromMap(new IdentityHashMap<JPackage, Boolean>());
|
||||
for (JPackage pkg : pkgMap.values()) {
|
||||
innerPackages.addAll(pkg.getInnerPackages());
|
||||
}
|
||||
// find root packages
|
||||
List<JPackage> rootPkgs = new ArrayList<JPackage>();
|
||||
for (JPackage pkg : pkgMap.values()) {
|
||||
if (!innerPackages.contains(pkg)) {
|
||||
rootPkgs.add(pkg);
|
||||
}
|
||||
}
|
||||
Collections.sort(rootPkgs);
|
||||
return rootPkgs;
|
||||
}
|
||||
|
||||
private void addPackage(Map<String, JPackage> pkgs, JPackage pkg) {
|
||||
String pkgName = pkg.getName();
|
||||
JPackage replaced = pkgs.put(pkgName, pkg);
|
||||
if (replaced != null) {
|
||||
pkg.getInnerPackages().addAll(replaced.getInnerPackages());
|
||||
pkg.getClasses().addAll(replaced.getClasses());
|
||||
}
|
||||
int dot = pkgName.lastIndexOf('.');
|
||||
if (dot > 0) {
|
||||
String prevPart = pkgName.substring(0, dot);
|
||||
String shortName = pkgName.substring(dot + 1);
|
||||
pkg.setName(shortName);
|
||||
JPackage prevPkg = pkgs.get(prevPart);
|
||||
if (prevPkg == null) {
|
||||
prevPkg = new JPackage(prevPart);
|
||||
addPackage(pkgs, prevPkg);
|
||||
}
|
||||
prevPkg.getInnerPackages().add(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return ROOT_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return "Source code";
|
||||
}
|
||||
}
|
||||
+29
-24
@@ -2,6 +2,7 @@ package jadx.gui.ui;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.utils.Position;
|
||||
|
||||
import javax.swing.JViewport;
|
||||
@@ -18,31 +19,26 @@ import java.awt.Rectangle;
|
||||
import org.fife.ui.rsyntaxtextarea.LinkGenerator;
|
||||
import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxScheme;
|
||||
import org.fife.ui.rsyntaxtextarea.Token;
|
||||
import org.fife.ui.rsyntaxtextarea.TokenTypes;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
class CodeArea extends RSyntaxTextArea {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CodeArea.class);
|
||||
class ContentArea extends RSyntaxTextArea {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ContentArea.class);
|
||||
|
||||
private static final long serialVersionUID = 6312736869579635796L;
|
||||
|
||||
public static final Color BACKGROUND = new Color(0xFAFAFA);
|
||||
public static final Color JUMP_TOKEN_FGD = new Color(0x491BA1);
|
||||
|
||||
private final CodePanel codePanel;
|
||||
private final JClass cls;
|
||||
private final ContentPanel contentPanel;
|
||||
private final JNode node;
|
||||
|
||||
CodeArea(CodePanel panel) {
|
||||
this.codePanel = panel;
|
||||
this.cls = panel.getCls();
|
||||
|
||||
setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
SyntaxScheme scheme = getSyntaxScheme();
|
||||
scheme.getStyle(Token.FUNCTION).foreground = Color.BLACK;
|
||||
ContentArea(ContentPanel panel) {
|
||||
this.contentPanel = panel;
|
||||
this.node = panel.getNode();
|
||||
|
||||
setMarkOccurrences(true);
|
||||
setBackground(BACKGROUND);
|
||||
@@ -54,12 +50,19 @@ class CodeArea extends RSyntaxTextArea {
|
||||
}
|
||||
caret.setVisible(true);
|
||||
|
||||
setHyperlinksEnabled(true);
|
||||
CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(cls);
|
||||
setLinkGenerator(codeLinkProcessor);
|
||||
addHyperlinkListener(codeLinkProcessor);
|
||||
setSyntaxEditingStyle(node.getSyntaxName());
|
||||
|
||||
setText(cls.getCode());
|
||||
if (node instanceof JClass) {
|
||||
SyntaxScheme scheme = getSyntaxScheme();
|
||||
scheme.getStyle(Token.FUNCTION).foreground = Color.BLACK;
|
||||
|
||||
setHyperlinksEnabled(true);
|
||||
CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator((JClass) node);
|
||||
setLinkGenerator(codeLinkProcessor);
|
||||
addHyperlinkListener(codeLinkProcessor);
|
||||
}
|
||||
|
||||
setText(node.getContent());
|
||||
}
|
||||
|
||||
private boolean isJumpToken(Token token) {
|
||||
@@ -71,9 +74,11 @@ class CodeArea extends RSyntaxTextArea {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Position pos = getPosition(cls, this, token.getOffset());
|
||||
if (pos != null) {
|
||||
return true;
|
||||
if (node instanceof JClass) {
|
||||
Position pos = getPosition((JClass) node, this, token.getOffset());
|
||||
if (pos != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -102,11 +107,11 @@ class CodeArea extends RSyntaxTextArea {
|
||||
}
|
||||
|
||||
Position getCurrentPosition() {
|
||||
return new Position(cls, getCaretLineNumber() + 1);
|
||||
return new Position(node, getCaretLineNumber() + 1);
|
||||
}
|
||||
|
||||
Integer getSourceLine(int line) {
|
||||
return cls.getCls().getSourceLine(line);
|
||||
return node.getSourceLine(line);
|
||||
}
|
||||
|
||||
void scrollToLine(int line) {
|
||||
@@ -172,7 +177,7 @@ class CodeArea extends RSyntaxTextArea {
|
||||
@Override
|
||||
public HyperlinkEvent execute() {
|
||||
return new HyperlinkEvent(defPos, HyperlinkEvent.EventType.ACTIVATED, null,
|
||||
defPos.getCls().getFullName());
|
||||
defPos.getNode().makeLongString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -192,7 +197,7 @@ class CodeArea extends RSyntaxTextArea {
|
||||
if (obj instanceof Position) {
|
||||
Position pos = (Position) obj;
|
||||
LOG.debug("Code jump to: {}", pos);
|
||||
TabbedPane tabbedPane = codePanel.getTabbedPane();
|
||||
TabbedPane tabbedPane = contentPanel.getTabbedPane();
|
||||
tabbedPane.getJumpManager().addPosition(getCurrentPosition());
|
||||
tabbedPane.getJumpManager().addPosition(pos);
|
||||
tabbedPane.showCode(pos);
|
||||
+15
-15
@@ -1,6 +1,6 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.utils.Utils;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
@@ -12,31 +12,31 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
class CodePanel extends JPanel {
|
||||
class ContentPanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 5310536092010045565L;
|
||||
|
||||
private final TabbedPane tabbedPane;
|
||||
private final JClass jClass;
|
||||
private final JNode node;
|
||||
private final SearchBar searchBar;
|
||||
private final CodeArea codeArea;
|
||||
private final ContentArea contentArea;
|
||||
private final JScrollPane scrollPane;
|
||||
|
||||
CodePanel(TabbedPane panel, JClass cls) {
|
||||
ContentPanel(TabbedPane panel, JNode node) {
|
||||
tabbedPane = panel;
|
||||
jClass = cls;
|
||||
codeArea = new CodeArea(this);
|
||||
searchBar = new SearchBar(codeArea);
|
||||
this.node = node;
|
||||
contentArea = new ContentArea(this);
|
||||
searchBar = new SearchBar(contentArea);
|
||||
|
||||
scrollPane = new JScrollPane(codeArea);
|
||||
scrollPane.setRowHeaderView(new LineNumbers(codeArea));
|
||||
scrollPane = new JScrollPane(contentArea);
|
||||
scrollPane.setRowHeaderView(new LineNumbers(contentArea));
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
add(searchBar, BorderLayout.NORTH);
|
||||
add(scrollPane);
|
||||
|
||||
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK);
|
||||
Utils.addKeyBinding(codeArea, key, "SearchAction", new SearchAction());
|
||||
Utils.addKeyBinding(contentArea, key, "SearchAction", new SearchAction());
|
||||
}
|
||||
|
||||
private class SearchAction extends AbstractAction {
|
||||
@@ -52,16 +52,16 @@ class CodePanel extends JPanel {
|
||||
return tabbedPane;
|
||||
}
|
||||
|
||||
JClass getCls() {
|
||||
return jClass;
|
||||
JNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
SearchBar getSearchBar() {
|
||||
return searchBar;
|
||||
}
|
||||
|
||||
CodeArea getCodeArea() {
|
||||
return codeArea;
|
||||
ContentArea getContentArea() {
|
||||
return contentArea;
|
||||
}
|
||||
|
||||
JScrollPane getScrollPane() {
|
||||
@@ -32,18 +32,18 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
|
||||
private static final int HEIGHT = Integer.MAX_VALUE - 1000000;
|
||||
private static final Color FOREGROUND = Color.GRAY;
|
||||
private static final Color BACKGROUND = CodeArea.BACKGROUND;
|
||||
private static final Color BACKGROUND = ContentArea.BACKGROUND;
|
||||
private static final Color CURRENT_LINE_FOREGROUND = new Color(227, 0, 0);
|
||||
|
||||
private CodeArea codeArea;
|
||||
private ContentArea contentArea;
|
||||
private boolean useSourceLines = true;
|
||||
|
||||
private int lastDigits;
|
||||
private int lastLine;
|
||||
private Map<String, FontMetrics> fonts;
|
||||
|
||||
public LineNumbers(CodeArea component) {
|
||||
this.codeArea = component;
|
||||
public LineNumbers(ContentArea component) {
|
||||
this.contentArea = component;
|
||||
setFont(component.getFont());
|
||||
setBackground(BACKGROUND);
|
||||
setForeground(FOREGROUND);
|
||||
@@ -70,7 +70,7 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
}
|
||||
|
||||
private void setPreferredWidth() {
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
Element root = contentArea.getDocument().getDefaultRootElement();
|
||||
int lines = root.getElementCount();
|
||||
int digits = Math.max(String.valueOf(lines).length(), 3);
|
||||
if (lastDigits != digits) {
|
||||
@@ -92,12 +92,12 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
FontMetrics fontMetrics = codeArea.getFontMetrics(codeArea.getFont());
|
||||
FontMetrics fontMetrics = contentArea.getFontMetrics(contentArea.getFont());
|
||||
Insets insets = getInsets();
|
||||
int availableWidth = getSize().width - insets.left - insets.right;
|
||||
Rectangle clip = g.getClipBounds();
|
||||
int rowStartOffset = codeArea.viewToModel(new Point(0, clip.y));
|
||||
int endOffset = codeArea.viewToModel(new Point(0, clip.y + clip.height));
|
||||
int rowStartOffset = contentArea.viewToModel(new Point(0, clip.y));
|
||||
int endOffset = contentArea.viewToModel(new Point(0, clip.y + clip.height));
|
||||
|
||||
while (rowStartOffset <= endOffset) {
|
||||
try {
|
||||
@@ -111,7 +111,7 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
int x = availableWidth - stringWidth + insets.left;
|
||||
int y = getOffsetY(rowStartOffset, fontMetrics);
|
||||
g.drawString(lineNumber, x, y);
|
||||
rowStartOffset = Utilities.getRowEnd(codeArea, rowStartOffset) + 1;
|
||||
rowStartOffset = Utilities.getRowEnd(contentArea, rowStartOffset) + 1;
|
||||
} catch (Exception e) {
|
||||
break;
|
||||
}
|
||||
@@ -119,19 +119,19 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
}
|
||||
|
||||
private boolean isCurrentLine(int rowStartOffset) {
|
||||
int caretPosition = codeArea.getCaretPosition();
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int caretPosition = contentArea.getCaretPosition();
|
||||
Element root = contentArea.getDocument().getDefaultRootElement();
|
||||
return root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition);
|
||||
}
|
||||
|
||||
protected String getTextLineNumber(int rowStartOffset) {
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
Element root = contentArea.getDocument().getDefaultRootElement();
|
||||
int index = root.getElementIndex(rowStartOffset);
|
||||
Element line = root.getElement(index);
|
||||
if (line.getStartOffset() == rowStartOffset) {
|
||||
int lineNumber = index + 1;
|
||||
if (useSourceLines) {
|
||||
Integer sourceLine = codeArea.getSourceLine(lineNumber);
|
||||
Integer sourceLine = contentArea.getSourceLine(lineNumber);
|
||||
if (sourceLine != null) {
|
||||
return String.valueOf(sourceLine);
|
||||
}
|
||||
@@ -143,7 +143,7 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
}
|
||||
|
||||
private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException {
|
||||
Rectangle r = codeArea.modelToView(rowStartOffset);
|
||||
Rectangle r = contentArea.modelToView(rowStartOffset);
|
||||
if (r == null) {
|
||||
throw new BadLocationException("Can't get Y offset", rowStartOffset);
|
||||
}
|
||||
@@ -156,7 +156,7 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
if (fonts == null) {
|
||||
fonts = new HashMap<String, FontMetrics>();
|
||||
}
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
Element root = contentArea.getDocument().getDefaultRootElement();
|
||||
int index = root.getElementIndex(rowStartOffset);
|
||||
Element line = root.getElement(index);
|
||||
for (int i = 0; i < line.getElementCount(); i++) {
|
||||
@@ -168,7 +168,7 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
FontMetrics fm = fonts.get(key);
|
||||
if (fm == null) {
|
||||
Font font = new Font(fontFamily, Font.PLAIN, fontSize);
|
||||
fm = codeArea.getFontMetrics(font);
|
||||
fm = contentArea.getFontMetrics(font);
|
||||
fonts.put(key, fm);
|
||||
}
|
||||
descent = Math.max(descent, fm.getDescent());
|
||||
@@ -179,8 +179,8 @@ public class LineNumbers extends JPanel implements CaretListener {
|
||||
|
||||
@Override
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
int caretPosition = codeArea.getCaretPosition();
|
||||
Element root = codeArea.getDocument().getDefaultRootElement();
|
||||
int caretPosition = contentArea.getCaretPosition();
|
||||
Element root = contentArea.getDocument().getDefaultRootElement();
|
||||
int currentLine = root.getElementIndex(caretPosition);
|
||||
if (lastLine != currentLine) {
|
||||
repaint();
|
||||
|
||||
@@ -3,6 +3,7 @@ package jadx.gui.ui;
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.JResource;
|
||||
import jadx.gui.treemodel.JRoot;
|
||||
import jadx.gui.update.JadxUpdate;
|
||||
import jadx.gui.update.JadxUpdate.IUpdateCallback;
|
||||
@@ -159,8 +160,12 @@ public class MainWindow extends JFrame {
|
||||
treeRoot = new JRoot(wrapper);
|
||||
treeRoot.setFlatPackages(isFlattenPackage);
|
||||
treeModel.setRoot(treeRoot);
|
||||
reloadTree();
|
||||
}
|
||||
|
||||
private void reloadTree() {
|
||||
treeModel.reload();
|
||||
tree.expandRow(0);
|
||||
tree.expandRow(1);
|
||||
}
|
||||
|
||||
private void toggleFlattenPackage() {
|
||||
@@ -178,37 +183,46 @@ public class MainWindow extends JFrame {
|
||||
if (root instanceof JRoot) {
|
||||
JRoot treeRoot = (JRoot) root;
|
||||
treeRoot.setFlatPackages(isFlattenPackage);
|
||||
treeModel.reload();
|
||||
tree.expandRow(0);
|
||||
reloadTree();
|
||||
}
|
||||
}
|
||||
|
||||
private void treeClickAction() {
|
||||
Object obj = tree.getLastSelectedPathComponent();
|
||||
if (obj instanceof JNode) {
|
||||
JNode node = (JNode) obj;
|
||||
JClass cls = node.getRootClass();
|
||||
if (cls != null) {
|
||||
tabbedPane.showCode(new Position(cls, node.getLine()));
|
||||
try {
|
||||
Object obj = tree.getLastSelectedPathComponent();
|
||||
if (obj instanceof JResource) {
|
||||
JResource res = (JResource) obj;
|
||||
if (res.getContent() != null) {
|
||||
tabbedPane.showCode(new Position(res, res.getLine()));
|
||||
}
|
||||
}
|
||||
if (obj instanceof JNode) {
|
||||
JNode node = (JNode) obj;
|
||||
JClass cls = node.getRootClass();
|
||||
if (cls != null) {
|
||||
tabbedPane.showCode(new Position(cls, node.getLine()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Content loading error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void syncWithEditor() {
|
||||
CodePanel selectedCodePanel = tabbedPane.getSelectedCodePanel();
|
||||
if (selectedCodePanel == null) {
|
||||
ContentPanel selectedContentPanel = tabbedPane.getSelectedCodePanel();
|
||||
if (selectedContentPanel == null) {
|
||||
return;
|
||||
}
|
||||
JClass jCls = selectedCodePanel.getCls();
|
||||
if (jCls.getParent() == null && treeRoot != null) {
|
||||
JNode node = selectedContentPanel.getNode();
|
||||
if (node.getParent() == null && treeRoot != null) {
|
||||
// node not register in tree
|
||||
jCls = treeRoot.searchClassInTree(jCls);
|
||||
if (jCls == null) {
|
||||
node = treeRoot.searchClassInTree(node);
|
||||
if (node == null) {
|
||||
LOG.error("Class not found in tree");
|
||||
return;
|
||||
}
|
||||
}
|
||||
TreeNode[] pathNodes = treeModel.getPathToRoot(jCls);
|
||||
TreeNode[] pathNodes = treeModel.getPathToRoot(node);
|
||||
if (pathNodes == null) {
|
||||
return;
|
||||
}
|
||||
@@ -218,9 +232,9 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
|
||||
private void toggleFind() {
|
||||
CodePanel codePanel = tabbedPane.getSelectedCodePanel();
|
||||
if (codePanel != null) {
|
||||
codePanel.getSearchBar().toggle();
|
||||
ContentPanel contentPanel = tabbedPane.getSelectedCodePanel();
|
||||
if (contentPanel != null) {
|
||||
contentPanel.getSearchBar().toggle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,8 +446,8 @@ public class MainWindow extends JFrame {
|
||||
tree.setCellRenderer(new DefaultTreeCellRenderer() {
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree,
|
||||
Object value, boolean selected, boolean expanded,
|
||||
boolean isLeaf, int row, boolean focused) {
|
||||
Object value, boolean selected, boolean expanded,
|
||||
boolean isLeaf, int row, boolean focused) {
|
||||
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused);
|
||||
if (value instanceof JNode) {
|
||||
setIcon(((JNode) value).getIcon());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.utils.JumpManager;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.Position;
|
||||
@@ -37,7 +37,7 @@ class TabbedPane extends JTabbedPane {
|
||||
private static final ImageIcon ICON_CLOSE_INACTIVE = Utils.openIcon("cross_grayed");
|
||||
|
||||
private final MainWindow mainWindow;
|
||||
private final Map<JClass, CodePanel> openTabs = new LinkedHashMap<JClass, CodePanel>();
|
||||
private final Map<JNode, ContentPanel> openTabs = new LinkedHashMap<JNode, ContentPanel>();
|
||||
private JumpManager jumps = new JumpManager();
|
||||
|
||||
TabbedPane(MainWindow window) {
|
||||
@@ -66,14 +66,14 @@ class TabbedPane extends JTabbedPane {
|
||||
}
|
||||
|
||||
void showCode(final Position pos) {
|
||||
final CodePanel codePanel = getCodePanel(pos.getCls());
|
||||
final ContentPanel contentPanel = getCodePanel(pos.getNode());
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setSelectedComponent(codePanel);
|
||||
CodeArea codeArea = codePanel.getCodeArea();
|
||||
codeArea.scrollToLine(pos.getLine());
|
||||
codeArea.requestFocus();
|
||||
setSelectedComponent(contentPanel);
|
||||
ContentArea contentArea = contentPanel.getContentArea();
|
||||
contentArea.scrollToLine(pos.getLine());
|
||||
contentArea.requestFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -96,40 +96,40 @@ class TabbedPane extends JTabbedPane {
|
||||
return jumps;
|
||||
}
|
||||
|
||||
private void addCodePanel(CodePanel codePanel) {
|
||||
openTabs.put(codePanel.getCls(), codePanel);
|
||||
add(codePanel);
|
||||
private void addCodePanel(ContentPanel contentPanel) {
|
||||
openTabs.put(contentPanel.getNode(), contentPanel);
|
||||
add(contentPanel);
|
||||
}
|
||||
|
||||
private void closeCodePanel(CodePanel codePanel) {
|
||||
openTabs.remove(codePanel.getCls());
|
||||
remove(codePanel);
|
||||
private void closeCodePanel(ContentPanel contentPanel) {
|
||||
openTabs.remove(contentPanel.getNode());
|
||||
remove(contentPanel);
|
||||
}
|
||||
|
||||
private CodePanel getCodePanel(JClass cls) {
|
||||
CodePanel panel = openTabs.get(cls);
|
||||
private ContentPanel getCodePanel(JNode cls) {
|
||||
ContentPanel panel = openTabs.get(cls);
|
||||
if (panel == null) {
|
||||
panel = new CodePanel(this, cls);
|
||||
panel = new ContentPanel(this, cls);
|
||||
addCodePanel(panel);
|
||||
setTabComponentAt(indexOfComponent(panel), makeTabComponent(panel));
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
CodePanel getSelectedCodePanel() {
|
||||
return (CodePanel) getSelectedComponent();
|
||||
ContentPanel getSelectedCodePanel() {
|
||||
return (ContentPanel) getSelectedComponent();
|
||||
}
|
||||
|
||||
private Component makeTabComponent(final CodePanel codePanel) {
|
||||
JClass cls = codePanel.getCls();
|
||||
String name = cls.getCls().getFullName();
|
||||
private Component makeTabComponent(final ContentPanel contentPanel) {
|
||||
JNode node = contentPanel.getNode();
|
||||
String name = node.makeLongString();
|
||||
|
||||
final JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0));
|
||||
panel.setOpaque(false);
|
||||
|
||||
final JLabel label = new JLabel(name);
|
||||
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
|
||||
label.setIcon(cls.getIcon());
|
||||
label.setIcon(node.getIcon());
|
||||
|
||||
final JButton button = new JButton();
|
||||
button.setIcon(ICON_CLOSE_INACTIVE);
|
||||
@@ -144,7 +144,7 @@ class TabbedPane extends JTabbedPane {
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
closeCodePanel(codePanel);
|
||||
closeCodePanel(contentPanel);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -152,13 +152,13 @@ class TabbedPane extends JTabbedPane {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (SwingUtilities.isMiddleMouseButton(e)) {
|
||||
closeCodePanel(codePanel);
|
||||
closeCodePanel(contentPanel);
|
||||
} else if (SwingUtilities.isRightMouseButton(e)) {
|
||||
JPopupMenu menu = createTabPopupMenu(codePanel);
|
||||
JPopupMenu menu = createTabPopupMenu(contentPanel);
|
||||
menu.show(panel, e.getX(), e.getY());
|
||||
} else {
|
||||
// TODO: make correct event delegation to tabbed pane
|
||||
setSelectedComponent(codePanel);
|
||||
setSelectedComponent(contentPanel);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -169,14 +169,14 @@ class TabbedPane extends JTabbedPane {
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPopupMenu createTabPopupMenu(final CodePanel codePanel) {
|
||||
private JPopupMenu createTabPopupMenu(final ContentPanel contentPanel) {
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
|
||||
JMenuItem closeTab = new JMenuItem(NLS.str("tabs.close"));
|
||||
closeTab.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
closeCodePanel(codePanel);
|
||||
closeCodePanel(contentPanel);
|
||||
}
|
||||
});
|
||||
menu.add(closeTab);
|
||||
@@ -186,9 +186,9 @@ class TabbedPane extends JTabbedPane {
|
||||
closeOther.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
List<CodePanel> codePanels = new ArrayList<CodePanel>(openTabs.values());
|
||||
for (CodePanel panel : codePanels) {
|
||||
if (panel != codePanel) {
|
||||
List<ContentPanel> contentPanels = new ArrayList<ContentPanel>(openTabs.values());
|
||||
for (ContentPanel panel : contentPanels) {
|
||||
if (panel != contentPanel) {
|
||||
closeCodePanel(panel);
|
||||
}
|
||||
}
|
||||
@@ -200,8 +200,8 @@ class TabbedPane extends JTabbedPane {
|
||||
closeAll.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
List<CodePanel> codePanels = new ArrayList<CodePanel>(openTabs.values());
|
||||
for (CodePanel panel : codePanels) {
|
||||
List<ContentPanel> contentPanels = new ArrayList<ContentPanel>(openTabs.values());
|
||||
for (ContentPanel panel : contentPanels) {
|
||||
closeCodePanel(panel);
|
||||
}
|
||||
}
|
||||
@@ -209,14 +209,14 @@ class TabbedPane extends JTabbedPane {
|
||||
menu.add(closeAll);
|
||||
menu.addSeparator();
|
||||
|
||||
CodePanel selectedCodePanel = getSelectedCodePanel();
|
||||
for (final Map.Entry<JClass, CodePanel> entry : openTabs.entrySet()) {
|
||||
final CodePanel cp = entry.getValue();
|
||||
if (cp == selectedCodePanel) {
|
||||
ContentPanel selectedContentPanel = getSelectedCodePanel();
|
||||
for (final Map.Entry<JNode, ContentPanel> entry : openTabs.entrySet()) {
|
||||
final ContentPanel cp = entry.getValue();
|
||||
if (cp == selectedContentPanel) {
|
||||
continue;
|
||||
}
|
||||
JClass jClass = entry.getKey();
|
||||
final String clsName = jClass.getCls().getFullName();
|
||||
JNode node = entry.getKey();
|
||||
final String clsName = node.makeLongString();
|
||||
JMenuItem item = new JMenuItem(clsName);
|
||||
item.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
@@ -224,7 +224,7 @@ class TabbedPane extends JTabbedPane {
|
||||
setSelectedComponent(cp);
|
||||
}
|
||||
});
|
||||
item.setIcon(jClass.getIcon());
|
||||
item.setIcon(node.getIcon());
|
||||
menu.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import org.slf4j.LoggerFactory;
|
||||
import static java.awt.Desktop.Action;
|
||||
|
||||
public class Link extends JLabel implements MouseListener {
|
||||
private static final long serialVersionUID = 3655322136444908178L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JLabel.class);
|
||||
|
||||
private String url;
|
||||
|
||||
@@ -4,6 +4,7 @@ import javax.swing.Icon;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class OverlayIcon implements Icon {
|
||||
@@ -19,6 +20,11 @@ public class OverlayIcon implements Icon {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public OverlayIcon(Icon icon, Icon... ovrIcons) {
|
||||
this.icon = icon;
|
||||
Collections.addAll(icons, ovrIcons);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return icon.getIconHeight();
|
||||
|
||||
@@ -2,23 +2,24 @@ package jadx.gui.utils;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
|
||||
public class Position {
|
||||
private final JClass cls;
|
||||
private final JNode node;
|
||||
private final int line;
|
||||
|
||||
public Position(CodePosition pos) {
|
||||
this.cls = new JClass(pos.getJavaClass());
|
||||
this.node = new JClass(pos.getJavaClass());
|
||||
this.line = pos.getLine();
|
||||
}
|
||||
|
||||
public Position(JClass cls, int line) {
|
||||
this.cls = cls;
|
||||
public Position(JNode node, int line) {
|
||||
this.node = node;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public JClass getCls() {
|
||||
return cls;
|
||||
public JNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
@@ -34,16 +35,16 @@ public class Position {
|
||||
return false;
|
||||
}
|
||||
Position position = (Position) obj;
|
||||
return line == position.line && cls.equals(position.cls);
|
||||
return line == position.line && node.equals(position.node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * cls.hashCode() + line;
|
||||
return 31 * node.hashCode() + line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Position: " + cls + " : " + line;
|
||||
return "Position: " + node + " : " + line;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user