diff --git a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java index a48d1d5e604eddfd8012a161e4d3afc31ae543f4..e0a1dc9ffadd8d1608568097cf115ded918a6024 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java @@ -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 getResources() { + return decompiler.getResources(); + } + public File getOpenFile() { return openFile; } 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 84998a0961da436294c1df4bac15066993a0f934..68d1a47989594972b95e71823bf6abbe68f5e13f 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java @@ -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(); diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java index fcd5957a11f4f827c9993ddbdcbc74b7219353c9..ca4459662f065490c7fcb71aee758989670ed1e9 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java @@ -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(); diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java new file mode 100644 index 0000000000000000000000000000000000000000..da5fed73d22a48f35efae397d7f86fd740fe8da6 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -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 { + 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 files = new ArrayList(1); + private final JResType type; + private final ResourceFile resFile; + + private boolean loaded; + private String content; + private Map 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 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(); + } + +} 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 a20631a32db3fb7b7321aa42884881e872c57395..74eaa29ad1ea43701dce2bee1437a15d4dd98aeb 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java @@ -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 rootPkgs = getHierarchyPackages(wrapper.getPackages()); - for (JPackage jPackage : rootPkgs) { - jPackage.update(); - add(jPackage); - } + add(new JSources(this, wrapper)); + + List 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 getHierarchyPackages(List packages) { - Map pkgMap = new HashMap(); - for (JavaPackage pkg : packages) { - addPackage(pkgMap, new JPackage(pkg)); + private List getHierarchyResources(List 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> 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 innerPackages = Collections.newSetFromMap(new IdentityHashMap()); - for (JPackage pkg : pkgMap.values()) { - innerPackages.addAll(pkg.getInnerPackages()); - } - // find root packages - List rootPkgs = new ArrayList(); - 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 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; diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JSources.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JSources.java new file mode 100644 index 0000000000000000000000000000000000000000..c82ddb40f27f258a99addba7e8318a3ae93d544f --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JSources.java @@ -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 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 getHierarchyPackages(List packages) { + Map pkgMap = new HashMap(); + 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> 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 innerPackages = Collections.newSetFromMap(new IdentityHashMap()); + for (JPackage pkg : pkgMap.values()) { + innerPackages.addAll(pkg.getInnerPackages()); + } + // find root packages + List rootPkgs = new ArrayList(); + for (JPackage pkg : pkgMap.values()) { + if (!innerPackages.contains(pkg)) { + rootPkgs.add(pkg); + } + } + Collections.sort(rootPkgs); + return rootPkgs; + } + + private void addPackage(Map 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"; + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java b/jadx-gui/src/main/java/jadx/gui/ui/ContentArea.java similarity index 80% rename from jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java rename to jadx-gui/src/main/java/jadx/gui/ui/ContentArea.java index 725bf103646b33293acf1e0b03ee2af4c189a235..f32c7d1adf18a4d91c64fc765b46388b3b049ecc 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/ContentArea.java @@ -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()); + + if (node instanceof JClass) { + SyntaxScheme scheme = getSyntaxScheme(); + scheme.getStyle(Token.FUNCTION).foreground = Color.BLACK; - setText(cls.getCode()); + 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); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/ContentPanel.java similarity index 65% rename from jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java rename to jadx-gui/src/main/java/jadx/gui/ui/ContentPanel.java index fe6de5fca57361a50d1702f91f23b4dff558b4fd..92b03871c801a0f6086d0ab37894983706da0426 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/ContentPanel.java @@ -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() { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java b/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java index b651ea5ba5abbdb6b71dcef42d5ce53b9906b1e5..2f971b5f510f7f514c384ba2d73f69dac6b9e71d 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java @@ -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 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(); } - 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(); 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 da04bf8d18c3c86c04b51c964b0a3da06c1fc6da..f801e54c8726c4428845cf8df5f397d5ef454275 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -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()); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java index c6a61e1aa4eaa532fa320132c89d23386da4d837..a4be0239ee3cfe683b3a20a506dc0e5eee54c3f0 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java @@ -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 openTabs = new LinkedHashMap(); + private final Map openTabs = new LinkedHashMap(); 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 codePanels = new ArrayList(openTabs.values()); - for (CodePanel panel : codePanels) { - if (panel != codePanel) { + List contentPanels = new ArrayList(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 codePanels = new ArrayList(openTabs.values()); - for (CodePanel panel : codePanels) { + List contentPanels = new ArrayList(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 entry : openTabs.entrySet()) { - final CodePanel cp = entry.getValue(); - if (cp == selectedCodePanel) { + ContentPanel selectedContentPanel = getSelectedCodePanel(); + for (final Map.Entry 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); } } diff --git a/jadx-gui/src/main/java/jadx/gui/utils/Link.java b/jadx-gui/src/main/java/jadx/gui/utils/Link.java index 033b59e93c73e5cfe9f39aed306f6e3c3dad3762..6b15445909db567826f405ca16487263da72df2a 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/Link.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/Link.java @@ -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; diff --git a/jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java b/jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java index ddb6e05501a6f63b011e681176a7b01ca00099fd..147245b31307dcccf6fb64fa9b4e25c930747efb 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/OverlayIcon.java @@ -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(); diff --git a/jadx-gui/src/main/java/jadx/gui/utils/Position.java b/jadx-gui/src/main/java/jadx/gui/utils/Position.java index 43ac156e00f604ea869d40400ea5430bdb24e4fb..8d6c99c5da914b00512ae8593006f35ac7828ef5 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/Position.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/Position.java @@ -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; } } diff --git a/jadx-gui/src/main/resources/icons-16/cf_obj.png b/jadx-gui/src/main/resources/icons-16/cf_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..1a02ea3eb3570ab8d8aa6ff01164b1f2a0339153 Binary files /dev/null and b/jadx-gui/src/main/resources/icons-16/cf_obj.png differ diff --git a/jadx-gui/src/main/resources/icons-16/error_co.png b/jadx-gui/src/main/resources/icons-16/error_co.png new file mode 100644 index 0000000000000000000000000000000000000000..d8f0680129e1d5e4ad1825dc156cdf44ef0bea8a Binary files /dev/null and b/jadx-gui/src/main/resources/icons-16/error_co.png differ diff --git a/jadx-gui/src/main/resources/icons-16/file_obj.png b/jadx-gui/src/main/resources/icons-16/file_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..4e9dc3802a41589f1c0ac74a6654e36f6cb80d0f Binary files /dev/null and b/jadx-gui/src/main/resources/icons-16/file_obj.png differ diff --git a/jadx-gui/src/main/resources/icons-16/java_ovr.png b/jadx-gui/src/main/resources/icons-16/java_ovr.png new file mode 100644 index 0000000000000000000000000000000000000000..11cf64acf23aa4a81f8e84823ad9b03c06b4a0a9 Binary files /dev/null and b/jadx-gui/src/main/resources/icons-16/java_ovr.png differ diff --git a/jadx-gui/src/main/resources/icons-16/packagefolder_obj.png b/jadx-gui/src/main/resources/icons-16/packagefolder_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..93053b772f5529aae3d02f2e27314b9ffa1f440f Binary files /dev/null and b/jadx-gui/src/main/resources/icons-16/packagefolder_obj.png differ diff --git a/jadx-gui/src/main/resources/icons-16/template_obj.png b/jadx-gui/src/main/resources/icons-16/template_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..4a7596a74b0c2010d2528945b3617a36fe13351c Binary files /dev/null and b/jadx-gui/src/main/resources/icons-16/template_obj.png differ diff --git a/jadx-gui/src/test/java/jadx/gui/treemodel/JRootTest.java b/jadx-gui/src/test/java/jadx/gui/treemodel/JSourcesTest.java similarity index 80% rename from jadx-gui/src/test/java/jadx/gui/treemodel/JRootTest.java rename to jadx-gui/src/test/java/jadx/gui/treemodel/JSourcesTest.java index 7e82957c412e342773a29737c8a6093935484cf6..a7eb730296d25e38d042194ea25529bcb7332b8d 100644 --- a/jadx-gui/src/test/java/jadx/gui/treemodel/JRootTest.java +++ b/jadx-gui/src/test/java/jadx/gui/treemodel/JSourcesTest.java @@ -16,15 +16,19 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -public class JRootTest { +public class JSourcesTest { - private JRoot root; + private JSources sources; private JadxDecompiler decompiler; @Before public void init() { - root = new JRoot(mock(JadxWrapper.class)); + JRoot root = mock(JRoot.class); + when(root.isFlatPackages()).thenReturn(false); + JadxWrapper wrapper = mock(JadxWrapper.class); + sources = new JSources(root, wrapper); decompiler = new JadxDecompiler(mock(IJadxArgs.class)); } @@ -33,7 +37,7 @@ public class JRootTest { String pkgName = "a.b.c.d.e"; List packages = Arrays.asList(newPkg(pkgName)); - List out = root.getHierarchyPackages(packages); + List out = sources.getHierarchyPackages(packages); assertEquals(out.size(), 1); JPackage jpkg = out.get(0); @@ -48,7 +52,7 @@ public class JRootTest { newPkg("a.c"), newPkg("a.d") ); - List out = root.getHierarchyPackages(packages); + List out = sources.getHierarchyPackages(packages); assertEquals(out.size(), 1); JPackage jpkg = out.get(0); @@ -64,7 +68,7 @@ public class JRootTest { newPkg("a.b.p2"), newPkg("a.b.p3") ); - List out = root.getHierarchyPackages(packages); + List out = sources.getHierarchyPackages(packages); assertEquals(out.size(), 1); JPackage jpkg = out.get(0); @@ -82,7 +86,7 @@ public class JRootTest { newPkg("d.e"), newPkg("d.f.a") ); - List out = root.getHierarchyPackages(packages); + List out = sources.getHierarchyPackages(packages); assertEquals(out.size(), 2); assertEquals(out.get(0).getName(), "a");