diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java index 31c68ea15..08b260229 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResContainer.java @@ -51,7 +51,7 @@ public class ResContainer implements Comparable { try { decoder.decode(content, os); } catch (Exception e) { - LOG.error("Failed to decode 9-patch png image", e); + LOG.error("Failed to decode 9-patch png image, path: {}", name, e); } newContent = new ByteArrayInputStream(os.toByteArray()); } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java index 62fd58d9b..c20060e8b 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java @@ -12,7 +12,7 @@ import jadx.core.dex.info.AccessInfo; import jadx.gui.utils.NLS; import jadx.gui.utils.Utils; -public class JClass extends JNode { +public class JClass extends JLoadableNode { private static final long serialVersionUID = -1239986875244097177L; private static final ImageIcon ICON_CLASS = Utils.openIcon("class_obj"); @@ -43,6 +43,11 @@ public class JClass extends JNode { return cls; } + @Override + public void loadNode() { + getRootClass().load(); + } + public synchronized void load() { if (!loaded) { cls.decompile(); diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JLoadableNode.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JLoadableNode.java new file mode 100644 index 000000000..b9aebdb29 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JLoadableNode.java @@ -0,0 +1,5 @@ +package jadx.gui.treemodel; + +public abstract class JLoadableNode extends JNode { + public abstract void loadNode(); +} diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java index 6affa73cd..fe68b2df7 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -6,16 +6,20 @@ import java.util.List; import java.util.Map; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.jetbrains.annotations.NotNull; import jadx.api.ResourceFile; import jadx.api.ResourceFileContent; import jadx.api.ResourceType; import jadx.core.codegen.CodeWriter; import jadx.core.xmlgen.ResContainer; +import jadx.gui.utils.NLS; import jadx.gui.utils.OverlayIcon; import jadx.gui.utils.Utils; -public class JResource extends JNode implements Comparable { +import static jadx.api.ResourceFileContent.createResourceFileContentInstance; + +public class JResource extends JLoadableNode implements Comparable { private static final long serialVersionUID = -201018424302612434L; private static final ImageIcon ROOT_ICON = Utils.openIcon("cf_obj"); @@ -50,22 +54,35 @@ public class JResource extends JNode implements Comparable { this.name = name; this.shortName = shortName; this.type = type; + this.loaded = false; } public final void update() { - loadContent(); removeAllChildren(); - for (JResource res : files) { - res.update(); - add(res); + if (!loaded) { + if (type == JResType.DIR + || type == JResType.ROOT + || resFile.getType() == ResourceType.ARSC) { + add(new TextNode(NLS.str("tree.loading"))); + } + } else { + loadContent(); + for (JResource res : files) { + res.update(); + add(res); + } } } + @Override + public void loadNode() { + loadContent(); + loaded = true; + update(); + } + private void loadContent() { getContent(); - for (JResource res : files) { - res.loadContent(); - } } @Override @@ -101,8 +118,8 @@ public class JResource extends JNode implements Comparable { String resName = rc.getName(); String[] path = resName.split("/"); String resShortName = path.length == 0 ? resName : path[path.length - 1]; - ResourceFileContent fileContent = ResourceFileContent.createResourceFileContentInstance(resShortName, ResourceType.XML, cw); - if(fileContent != null) { + ResourceFileContent fileContent = createResourceFileContentInstance(resShortName, ResourceType.XML, cw); + if (fileContent != null) { addPath(path, root, new JResource(fileContent, resName, resShortName, JResType.FILE)); } } @@ -242,7 +259,7 @@ public class JResource extends JNode implements Comparable { } @Override - public int compareTo(JResource o) { + public int compareTo(@NotNull JResource o) { return name.compareTo(o.name); } @@ -266,5 +283,4 @@ public class JResource extends JNode implements Comparable { public int hashCode() { return name.hashCode(); } - } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java index ac088b294..05fb9c114 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java @@ -10,6 +10,7 @@ import java.util.regex.Pattern; import jadx.api.ResourceFile; import jadx.gui.JadxWrapper; import jadx.gui.treemodel.JResource.JResType; +import jadx.gui.utils.NLS; import jadx.gui.utils.Utils; public class JRoot extends JNode { @@ -41,7 +42,7 @@ public class JRoot extends JNode { if (resources.isEmpty()) { return Collections.emptyList(); } - JResource root = new JResource(null, "Resources", JResType.ROOT); + JResource root = new JResource(null, NLS.str("tree.resources_title"), JResType.ROOT); String splitPathStr = Pattern.quote(File.separator); for (ResourceFile rf : resources) { String rfName; diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JSources.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JSources.java index 9c19e6893..a0208e1ac 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JSources.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JSources.java @@ -12,6 +12,7 @@ import java.util.Set; import jadx.api.JavaPackage; import jadx.gui.JadxWrapper; +import jadx.gui.utils.NLS; import jadx.gui.utils.Utils; public class JSources extends JNode { @@ -132,6 +133,6 @@ public class JSources extends JNode { @Override public String makeString() { - return "Source code"; + return NLS.str("tree.sources_title"); } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index e2cec158e..695a2809a 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -41,6 +41,7 @@ import jadx.gui.jobs.IndexJob; import jadx.gui.settings.JadxSettings; import jadx.gui.settings.JadxSettingsWindow; import jadx.gui.treemodel.JClass; +import jadx.gui.treemodel.JLoadableNode; import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JResource; import jadx.gui.treemodel.JRoot; @@ -581,9 +582,8 @@ public class MainWindow extends JFrame { public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException { TreePath path = event.getPath(); Object node = path.getLastPathComponent(); - if (node instanceof JClass) { - JClass cls = (JClass) node; - cls.getRootClass().load(); + if (node instanceof JLoadableNode) { + ((JLoadableNode) node).loadNode(); } } diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 577311e17..69e66989b 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -23,6 +23,8 @@ file.save_all_msg=Select directory for save decompiled sources file.select=Select file.exit=Exit +tree.sources_title=Source code +tree.resources_title=Resources tree.loading=Loading... search=Search