summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java56
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java12
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java102
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java31
-rw-r--r--enigma-swing/src/main/resources/icons/class.pngbin0 -> 408 bytes
-rw-r--r--enigma-swing/src/main/resources/icons/field.pngbin0 -> 392 bytes
-rw-r--r--enigma-swing/src/main/resources/icons/method.pngbin0 -> 618 bytes
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java109
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java24
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java27
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java3
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java7
-rw-r--r--enigma/src/main/resources/lang/en_us.json2
-rw-r--r--enigma/src/main/resources/lang/fr_fr.json2
14 files changed, 338 insertions, 37 deletions
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
index c56731d..a3a438e 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -51,10 +51,7 @@ import cuchaz.enigma.network.packet.RemoveMappingC2SPacket;
51import cuchaz.enigma.network.packet.RenameC2SPacket; 51import cuchaz.enigma.network.packet.RenameC2SPacket;
52import cuchaz.enigma.source.Token; 52import cuchaz.enigma.source.Token;
53import cuchaz.enigma.translation.mapping.EntryRemapper; 53import cuchaz.enigma.translation.mapping.EntryRemapper;
54import cuchaz.enigma.translation.representation.entry.ClassEntry; 54import cuchaz.enigma.translation.representation.entry.*;
55import cuchaz.enigma.translation.representation.entry.Entry;
56import cuchaz.enigma.translation.representation.entry.FieldEntry;
57import cuchaz.enigma.translation.representation.entry.MethodEntry;
58import cuchaz.enigma.utils.I18n; 55import cuchaz.enigma.utils.I18n;
59import cuchaz.enigma.utils.validation.ParameterizedMessage; 56import cuchaz.enigma.utils.validation.ParameterizedMessage;
60import cuchaz.enigma.utils.validation.ValidationContext; 57import cuchaz.enigma.utils.validation.ValidationContext;
@@ -82,6 +79,7 @@ public class Gui implements LanguageChangeListener {
82 private JPanel classesPanel; 79 private JPanel classesPanel;
83 private JSplitPane splitClasses; 80 private JSplitPane splitClasses;
84 private IdentifierPanel infoPanel; 81 private IdentifierPanel infoPanel;
82 private StructurePanel structurePanel;
85 private JTree inheritanceTree; 83 private JTree inheritanceTree;
86 private JTree implementationsTree; 84 private JTree implementationsTree;
87 private JTree callsTree; 85 private JTree callsTree;
@@ -163,6 +161,9 @@ public class Gui implements LanguageChangeListener {
163 // init info panel 161 // init info panel
164 infoPanel = new IdentifierPanel(this); 162 infoPanel = new IdentifierPanel(this);
165 163
164 // init structure panel
165 this.structurePanel = new StructurePanel(this);
166
166 // init inheritance panel 167 // init inheritance panel
167 inheritanceTree = new JTree(); 168 inheritanceTree = new JTree();
168 inheritanceTree.setModel(null); 169 inheritanceTree.setModel(null);
@@ -287,6 +288,8 @@ public class Gui implements LanguageChangeListener {
287 editorTabPopupMenu.show(openFiles, e.getX(), e.getY(), EditorPanel.byUi(openFiles.getComponentAt(i))); 288 editorTabPopupMenu.show(openFiles, e.getX(), e.getY(), EditorPanel.byUi(openFiles.getComponentAt(i)));
288 } 289 }
289 } 290 }
291
292 showStructure(getActiveEditor());
290 } 293 }
291 }); 294 });
292 295
@@ -311,6 +314,7 @@ public class Gui implements LanguageChangeListener {
311 centerPanel.add(openFiles, BorderLayout.CENTER); 314 centerPanel.add(openFiles, BorderLayout.CENTER);
312 tabs = new JTabbedPane(); 315 tabs = new JTabbedPane();
313 tabs.setPreferredSize(ScaleUtil.getDimension(250, 0)); 316 tabs.setPreferredSize(ScaleUtil.getDimension(250, 0));
317 tabs.addTab(I18n.translate("info_panel.tree.structure"), structurePanel);
314 tabs.addTab(I18n.translate("info_panel.tree.inheritance"), inheritancePanel); 318 tabs.addTab(I18n.translate("info_panel.tree.inheritance"), inheritancePanel);
315 tabs.addTab(I18n.translate("info_panel.tree.implementations"), implementationsPanel); 319 tabs.addTab(I18n.translate("info_panel.tree.implementations"), implementationsPanel);
316 tabs.addTab(I18n.translate("info_panel.tree.calls"), callPanel); 320 tabs.addTab(I18n.translate("info_panel.tree.calls"), callPanel);
@@ -482,11 +486,14 @@ public class Gui implements LanguageChangeListener {
482 } 486 }
483 }); 487 });
484 488
489 showStructure(ed);
490
485 return ed; 491 return ed;
486 }); 492 });
487 if (editorPanel != null) { 493 if (editorPanel != null) {
488 openFiles.setSelectedComponent(editors.get(entry).getUi()); 494 openFiles.setSelectedComponent(editors.get(entry).getUi());
489 } 495 }
496
490 return editorPanel; 497 return editorPanel;
491 } 498 }
492 499
@@ -506,6 +513,7 @@ public class Gui implements LanguageChangeListener {
506 public void closeEditor(EditorPanel ed) { 513 public void closeEditor(EditorPanel ed) {
507 openFiles.remove(ed.getUi()); 514 openFiles.remove(ed.getUi());
508 editors.inverse().remove(ed); 515 editors.inverse().remove(ed);
516 showStructure(getActiveEditor());
509 ed.destroy(); 517 ed.destroy();
510 } 518 }
511 519
@@ -595,6 +603,32 @@ public class Gui implements LanguageChangeListener {
595 infoPanel.startRenaming(); 603 infoPanel.startRenaming();
596 } 604 }
597 605
606 public void showStructure(EditorPanel editor) {
607 JTree structureTree = this.structurePanel.getStructureTree();
608 structureTree.setModel(null);
609
610 if (editor == null) {
611 this.structurePanel.getSortingPanel().setVisible(false);
612 return;
613 }
614
615 ClassEntry classEntry = editor.getClassHandle().getRef();
616 if (classEntry == null) return;
617
618 this.structurePanel.getSortingPanel().setVisible(true);
619
620 // get the class structure
621 StructureTreeNode node = this.controller.getClassStructure(classEntry, this.structurePanel.shouldHideDeobfuscated());
622
623 // show the tree at the root
624 TreePath path = getPathToRoot(node);
625 structureTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
626 structureTree.expandPath(path);
627 structureTree.setSelectionRow(structureTree.getRowForPath(path));
628
629 redraw();
630 }
631
598 public void showInheritance(EditorPanel editor) { 632 public void showInheritance(EditorPanel editor) {
599 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); 633 EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
600 if (cursorReference == null) return; 634 if (cursorReference == null) return;
@@ -621,7 +655,7 @@ public class Gui implements LanguageChangeListener {
621 inheritanceTree.setSelectionRow(inheritanceTree.getRowForPath(path)); 655 inheritanceTree.setSelectionRow(inheritanceTree.getRowForPath(path));
622 } 656 }
623 657
624 tabs.setSelectedIndex(0); 658 tabs.setSelectedIndex(1);
625 659
626 redraw(); 660 redraw();
627 } 661 }
@@ -649,7 +683,7 @@ public class Gui implements LanguageChangeListener {
649 implementationsTree.setSelectionRow(implementationsTree.getRowForPath(path)); 683 implementationsTree.setSelectionRow(implementationsTree.getRowForPath(path));
650 } 684 }
651 685
652 tabs.setSelectedIndex(1); 686 tabs.setSelectedIndex(2);
653 687
654 redraw(); 688 redraw();
655 } 689 }
@@ -669,7 +703,7 @@ public class Gui implements LanguageChangeListener {
669 callsTree.setModel(new DefaultTreeModel(node)); 703 callsTree.setModel(new DefaultTreeModel(node));
670 } 704 }
671 705
672 tabs.setSelectedIndex(2); 706 tabs.setSelectedIndex(3);
673 707
674 redraw(); 708 redraw();
675 } 709 }
@@ -893,9 +927,10 @@ public class Gui implements LanguageChangeListener {
893 public void retranslateUi() { 927 public void retranslateUi() {
894 this.jarFileChooser.setTitle(I18n.translate("menu.file.jar.open")); 928 this.jarFileChooser.setTitle(I18n.translate("menu.file.jar.open"));
895 this.exportJarFileChooser.setTitle(I18n.translate("menu.file.export.jar")); 929 this.exportJarFileChooser.setTitle(I18n.translate("menu.file.export.jar"));
896 this.tabs.setTitleAt(0, I18n.translate("info_panel.tree.inheritance")); 930 this.tabs.setTitleAt(0, I18n.translate("info_panel.tree.structure"));
897 this.tabs.setTitleAt(1, I18n.translate("info_panel.tree.implementations")); 931 this.tabs.setTitleAt(1, I18n.translate("info_panel.tree.inheritance"));
898 this.tabs.setTitleAt(2, I18n.translate("info_panel.tree.calls")); 932 this.tabs.setTitleAt(2, I18n.translate("info_panel.tree.implementations"));
933 this.tabs.setTitleAt(3, I18n.translate("info_panel.tree.calls"));
899 this.logTabs.setTitleAt(0, I18n.translate("log_panel.users")); 934 this.logTabs.setTitleAt(0, I18n.translate("log_panel.users"));
900 this.logTabs.setTitleAt(1, I18n.translate("log_panel.messages")); 935 this.logTabs.setTitleAt(1, I18n.translate("log_panel.messages"));
901 this.connectionStatusLabel.setText(I18n.translate(connectionState == ConnectionState.NOT_CONNECTED ? "status.disconnected" : "status.connected")); 936 this.connectionStatusLabel.setText(I18n.translate(connectionState == ConnectionState.NOT_CONNECTED ? "status.disconnected" : "status.connected"));
@@ -907,6 +942,7 @@ public class Gui implements LanguageChangeListener {
907 this.deobfPanel.retranslateUi(); 942 this.deobfPanel.retranslateUi();
908 this.deobfPanelPopupMenu.retranslateUi(); 943 this.deobfPanelPopupMenu.retranslateUi();
909 this.infoPanel.retranslateUi(); 944 this.infoPanel.retranslateUi();
945 this.structurePanel.retranslateUi();
910 this.editors.values().forEach(EditorPanel::retranslateUi); 946 this.editors.values().forEach(EditorPanel::retranslateUi);
911 } 947 }
912 948
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
index 4f7819e..4e964da 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -57,10 +57,7 @@ import cuchaz.enigma.translation.mapping.serde.MappingParseException;
57import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 57import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
58import cuchaz.enigma.translation.mapping.tree.EntryTree; 58import cuchaz.enigma.translation.mapping.tree.EntryTree;
59import cuchaz.enigma.translation.mapping.tree.HashEntryTree; 59import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
60import cuchaz.enigma.translation.representation.entry.ClassEntry; 60import cuchaz.enigma.translation.representation.entry.*;
61import cuchaz.enigma.translation.representation.entry.Entry;
62import cuchaz.enigma.translation.representation.entry.FieldEntry;
63import cuchaz.enigma.translation.representation.entry.MethodEntry;
64import cuchaz.enigma.utils.I18n; 61import cuchaz.enigma.utils.I18n;
65import cuchaz.enigma.utils.Utils; 62import cuchaz.enigma.utils.Utils;
66import cuchaz.enigma.utils.validation.ValidationContext; 63import cuchaz.enigma.utils.validation.ValidationContext;
@@ -395,6 +392,13 @@ public class GuiController implements ClientPacketHandler {
395 chp.invalidateMapped(); 392 chp.invalidateMapped();
396 } 393 }
397 394
395 public StructureTreeNode getClassStructure(ClassEntry entry, boolean hideDeobfuscated) {
396 Translator translator = this.project.getMapper().getDeobfuscator();
397 StructureTreeNode rootNode = new StructureTreeNode(translator, entry, entry);
398 rootNode.load(this.project.getJarIndex(), hideDeobfuscated);
399 return rootNode;
400 }
401
398 public ClassInheritanceTreeNode getClassInheritance(ClassEntry entry) { 402 public ClassInheritanceTreeNode getClassInheritance(ClassEntry entry) {
399 Translator translator = project.getMapper().getDeobfuscator(); 403 Translator translator = project.getMapper().getDeobfuscator();
400 ClassInheritanceTreeNode rootNode = indexTreeBuilder.buildClassInheritance(translator, entry); 404 ClassInheritanceTreeNode rootNode = indexTreeBuilder.buildClassInheritance(translator, entry);
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java
new file mode 100644
index 0000000..32f803f
--- /dev/null
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java
@@ -0,0 +1,102 @@
1package cuchaz.enigma.gui.panels;
2
3import cuchaz.enigma.analysis.StructureTreeNode;
4import cuchaz.enigma.gui.Gui;
5import cuchaz.enigma.gui.util.GuiUtil;
6import cuchaz.enigma.translation.representation.entry.ClassEntry;
7import cuchaz.enigma.translation.representation.entry.FieldEntry;
8import cuchaz.enigma.translation.representation.entry.MethodEntry;
9import cuchaz.enigma.translation.representation.entry.ParentedEntry;
10import cuchaz.enigma.utils.I18n;
11
12import javax.swing.*;
13import javax.swing.tree.TreeCellRenderer;
14import javax.swing.tree.TreePath;
15import java.awt.*;
16import java.awt.event.MouseAdapter;
17import java.awt.event.MouseEvent;
18
19public class StructurePanel extends JPanel {
20 private final Gui gui;
21
22 private JPanel sortingPanel;
23 private JCheckBox hideDeobfuscated;
24
25 private JTree structureTree;
26
27 public StructurePanel(Gui gui) {
28 this.gui = gui;
29
30 this.sortingPanel = new JPanel();
31 this.hideDeobfuscated = new JCheckBox(I18n.translate("info_panel.tree.structure.hide_deobfuscated"));
32 this.hideDeobfuscated.addActionListener(event -> gui.showStructure(gui.getActiveEditor()));
33 this.sortingPanel.add(this.hideDeobfuscated);
34 this.sortingPanel.setVisible(false);
35
36 this.structureTree = new JTree();
37 this.structureTree.setModel(null);
38 this.structureTree.setCellRenderer(new StructureTreeCellRenderer());
39 this.structureTree.addMouseListener(new MouseAdapter() {
40 @Override
41 public void mouseClicked(MouseEvent event) {
42 if (event.getClickCount() >= 2) {
43 // get the selected node
44 TreePath path = structureTree.getSelectionPath();
45 if (path == null) {
46 return;
47 }
48
49 Object node = path.getLastPathComponent();
50 if (node instanceof StructureTreeNode) {
51 gui.getController().navigateTo(((StructureTreeNode) node).getEntry());
52 }
53 }
54 }
55 });
56
57 this.setLayout(new BorderLayout());
58 this.add(this.sortingPanel, BorderLayout.NORTH);
59 this.add(new JScrollPane(this.structureTree));
60 }
61
62 public JPanel getSortingPanel() {
63 return this.sortingPanel;
64 }
65
66 public boolean shouldHideDeobfuscated() {
67 return this.hideDeobfuscated.isSelected();
68 }
69
70 public JTree getStructureTree() {
71 return this.structureTree;
72 }
73
74 public void retranslateUi() {
75 this.hideDeobfuscated.setText(I18n.translate("info_panel.tree.structure.hide_deobfuscated"));
76 }
77
78 class StructureTreeCellRenderer implements TreeCellRenderer {
79 private JLabel label;
80
81 public StructureTreeCellRenderer() {
82 this.label = new JLabel();
83 }
84
85 @Override
86 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
87 ParentedEntry entry = ((StructureTreeNode) value).getEntry();
88
89 if (entry instanceof ClassEntry) {
90 this.label.setIcon(GuiUtil.CLASS_ICON);
91 } else if (entry instanceof MethodEntry) {
92 this.label.setIcon(GuiUtil.METHOD_ICON);
93 } else if (entry instanceof FieldEntry) {
94 this.label.setIcon(GuiUtil.FIELD_ICON);
95 }
96
97 this.label.setText(value.toString());
98
99 return this.label;
100 }
101 }
102}
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java
index 7fe942d..666fc0a 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java
@@ -1,24 +1,24 @@
1package cuchaz.enigma.gui.util; 1package cuchaz.enigma.gui.util;
2 2
3import java.awt.Color; 3import cuchaz.enigma.utils.Os;
4import java.awt.Cursor; 4
5import java.awt.Desktop; 5import javax.imageio.ImageIO;
6import java.awt.Font; 6import javax.swing.*;
7import java.awt.*;
7import java.awt.event.MouseAdapter; 8import java.awt.event.MouseAdapter;
8import java.awt.event.MouseEvent; 9import java.awt.event.MouseEvent;
9import java.awt.font.TextAttribute; 10import java.awt.font.TextAttribute;
10import java.io.IOException; 11import java.io.IOException;
12import java.io.InputStream;
11import java.net.URI; 13import java.net.URI;
12import java.net.URISyntaxException; 14import java.net.URISyntaxException;
13import java.util.Map; 15import java.util.Map;
14 16
15import javax.swing.JComponent;
16import javax.swing.JLabel;
17import javax.swing.ToolTipManager;
18
19import cuchaz.enigma.utils.Os;
20
21public class GuiUtil { 17public class GuiUtil {
18 public static final Icon CLASS_ICON = loadIcon("class");
19 public static final Icon METHOD_ICON = loadIcon("method");
20 public static final Icon FIELD_ICON = loadIcon("field");
21
22 public static void openUrl(String url) { 22 public static void openUrl(String url) {
23 try { 23 try {
24 switch (Os.getOs()) { 24 switch (Os.getOs()) {
@@ -70,4 +70,15 @@ public class GuiUtil {
70 return link; 70 return link;
71 } 71 }
72 72
73 public static Icon loadIcon(String name) {
74 try {
75 InputStream inputStream = GuiUtil.class.getResourceAsStream("/icons/" + name + ".png");
76 Image image = ImageIO.read(inputStream).getScaledInstance(ScaleUtil.scale(16), ScaleUtil.scale(16), Image.SCALE_DEFAULT);
77 return new ImageIcon(image);
78 } catch (IOException e) {
79 e.printStackTrace();
80 }
81
82 return null;
83 }
73} 84}
diff --git a/enigma-swing/src/main/resources/icons/class.png b/enigma-swing/src/main/resources/icons/class.png
new file mode 100644
index 0000000..4f7d0f4
--- /dev/null
+++ b/enigma-swing/src/main/resources/icons/class.png
Binary files differ
diff --git a/enigma-swing/src/main/resources/icons/field.png b/enigma-swing/src/main/resources/icons/field.png
new file mode 100644
index 0000000..b124dcf
--- /dev/null
+++ b/enigma-swing/src/main/resources/icons/field.png
Binary files differ
diff --git a/enigma-swing/src/main/resources/icons/method.png b/enigma-swing/src/main/resources/icons/method.png
new file mode 100644
index 0000000..4ed0ccc
--- /dev/null
+++ b/enigma-swing/src/main/resources/icons/method.png
Binary files differ
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
new file mode 100644
index 0000000..13f277c
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
@@ -0,0 +1,109 @@
1package cuchaz.enigma.analysis;
2
3import cuchaz.enigma.analysis.index.JarIndex;
4import cuchaz.enigma.translation.Translator;
5import cuchaz.enigma.translation.representation.TypeDescriptor;
6import cuchaz.enigma.translation.representation.entry.*;
7
8import javax.swing.tree.DefaultMutableTreeNode;
9import java.util.List;
10
11public class StructureTreeNode extends DefaultMutableTreeNode {
12 private final Translator translator;
13 private final ClassEntry parentEntry;
14 private final ParentedEntry entry;
15
16 public StructureTreeNode(Translator translator, ClassEntry parentEntry, ParentedEntry entry) {
17 this.translator = translator;
18 this.parentEntry = parentEntry;
19 this.entry = entry;
20 }
21
22 /**
23 * Returns the parented entry corresponding to this tree node.
24 */
25 public ParentedEntry getEntry() {
26 return this.entry;
27 }
28
29 public void load(JarIndex jarIndex, boolean hideDeobfuscated) {
30 List<ParentedEntry> children = jarIndex.getChildrenByClass().get(this.parentEntry);
31
32 for (ParentedEntry child : children) {
33 StructureTreeNode childNode = new StructureTreeNode(this.translator, this.parentEntry, child);
34
35 if (child instanceof ClassEntry) {
36 childNode = new StructureTreeNode(this.translator, (ClassEntry) child, child);
37 childNode.load(jarIndex, hideDeobfuscated);
38 }
39
40 // don't add deobfuscated members if hideDeobfuscated is true, unless it's an inner class
41 if (hideDeobfuscated && this.translator.extendedTranslate(child).isDeobfuscated() && !(child instanceof ClassEntry)) {
42 continue;
43 }
44
45 // don't add constructor methods if hideDeobfuscated is true
46 if (hideDeobfuscated && (child instanceof MethodEntry) && ((MethodEntry) child).isConstructor()) {
47 continue;
48 }
49
50 this.add(childNode);
51 }
52 }
53
54 @Override
55 public String toString() {
56 ParentedEntry translatedEntry = this.translator.extendedTranslate(this.entry).getValue();
57 String result = translatedEntry.getName();
58
59 if (this.entry instanceof FieldDefEntry) {
60 FieldDefEntry field = (FieldDefEntry) translatedEntry;
61 String returnType = this.parseDesc(field.getDesc());
62
63 result = result + ": " + returnType;
64 } else if (this.entry instanceof MethodDefEntry) {
65 MethodDefEntry method = (MethodDefEntry) translatedEntry;
66 String args = this.parseArgs(method.getDesc().getArgumentDescs());
67 String returnType = this.parseDesc(method.getDesc().getReturnDesc());
68
69 if (method.isConstructor()) {
70 result = method.getParent().getSimpleName() + args;
71 } else {
72 result = result + args + ": " + returnType;
73 }
74 }
75
76 return result;
77 }
78
79 private String parseArgs(List<TypeDescriptor> args) {
80 if (args.size() > 0) {
81 String result = "(";
82
83 for (int i = 0; i < args.size(); i++) {
84 if (i > 0) {
85 result += ", ";
86 }
87
88 result += this.parseDesc(args.get(i));
89 }
90
91 return result + ")";
92 }
93
94 return "()";
95 }
96
97 private String parseDesc(TypeDescriptor desc) {
98 if (desc.isVoid()) return "void";
99 if (desc.isPrimitive()) return desc.getPrimitive().getKeyword();
100 if (desc.isType()) return desc.getTypeEntry().getSimpleName();
101
102 if (desc.isArray()) {
103 if (desc.getArrayType().isPrimitive()) return desc.getArrayType().getPrimitive().getKeyword() + "[]";
104 if (desc.getArrayType().isType()) return desc.getArrayType().getTypeEntry().getSimpleName() + "[]";
105 }
106
107 return null;
108 }
109}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
index b5ad91a..d41731f 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
@@ -23,10 +23,7 @@ import cuchaz.enigma.translation.representation.Lambda;
23import cuchaz.enigma.translation.representation.entry.*; 23import cuchaz.enigma.translation.representation.entry.*;
24import cuchaz.enigma.utils.I18n; 24import cuchaz.enigma.utils.I18n;
25 25
26import java.util.Arrays; 26import java.util.*;
27import java.util.Collection;
28import java.util.HashSet;
29import java.util.Set;
30 27
31public class JarIndex implements JarIndexer { 28public class JarIndex implements JarIndexer {
32 private final Set<String> indexedClasses = new HashSet<>(); 29 private final Set<String> indexedClasses = new HashSet<>();
@@ -40,6 +37,7 @@ public class JarIndex implements JarIndexer {
40 private final Collection<JarIndexer> indexers; 37 private final Collection<JarIndexer> indexers;
41 38
42 private final Multimap<String, MethodDefEntry> methodImplementations = HashMultimap.create(); 39 private final Multimap<String, MethodDefEntry> methodImplementations = HashMultimap.create();
40 private final Map<ClassEntry, List<ParentedEntry>> childrenByClass;
43 41
44 public JarIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex, BridgeMethodIndex bridgeMethodIndex, PackageVisibilityIndex packageVisibilityIndex) { 42 public JarIndex(EntryIndex entryIndex, InheritanceIndex inheritanceIndex, ReferenceIndex referenceIndex, BridgeMethodIndex bridgeMethodIndex, PackageVisibilityIndex packageVisibilityIndex) {
45 this.entryIndex = entryIndex; 43 this.entryIndex = entryIndex;
@@ -49,6 +47,7 @@ public class JarIndex implements JarIndexer {
49 this.packageVisibilityIndex = packageVisibilityIndex; 47 this.packageVisibilityIndex = packageVisibilityIndex;
50 this.indexers = Arrays.asList(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); 48 this.indexers = Arrays.asList(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex);
51 this.entryResolver = new IndexEntryResolver(this); 49 this.entryResolver = new IndexEntryResolver(this);
50 this.childrenByClass = new HashMap<>();
52 } 51 }
53 52
54 public static JarIndex empty() { 53 public static JarIndex empty() {
@@ -101,6 +100,11 @@ public class JarIndex implements JarIndexer {
101 } 100 }
102 101
103 indexers.forEach(indexer -> indexer.indexClass(classEntry)); 102 indexers.forEach(indexer -> indexer.indexClass(classEntry));
103 childrenByClass.putIfAbsent(classEntry, new ArrayList<>());
104 if (classEntry.isInnerClass() && !classEntry.getAccess().isSynthetic()) {
105 childrenByClass.putIfAbsent(classEntry.getParent(), new ArrayList<>());
106 childrenByClass.get(classEntry.getParent()).add(classEntry);
107 }
104 } 108 }
105 109
106 @Override 110 @Override
@@ -110,6 +114,10 @@ public class JarIndex implements JarIndexer {
110 } 114 }
111 115
112 indexers.forEach(indexer -> indexer.indexField(fieldEntry)); 116 indexers.forEach(indexer -> indexer.indexField(fieldEntry));
117 if (!fieldEntry.getAccess().isSynthetic()) {
118 childrenByClass.putIfAbsent(fieldEntry.getParent(), new ArrayList<>());
119 childrenByClass.get(fieldEntry.getParent()).add(fieldEntry);
120 }
113 } 121 }
114 122
115 @Override 123 @Override
@@ -119,6 +127,10 @@ public class JarIndex implements JarIndexer {
119 } 127 }
120 128
121 indexers.forEach(indexer -> indexer.indexMethod(methodEntry)); 129 indexers.forEach(indexer -> indexer.indexMethod(methodEntry));
130 if (!methodEntry.getAccess().isSynthetic() && !methodEntry.getName().equals("<clinit>")) {
131 childrenByClass.putIfAbsent(methodEntry.getParent(), new ArrayList<>());
132 childrenByClass.get(methodEntry.getParent()).add(methodEntry);
133 }
122 134
123 if (!methodEntry.isConstructor()) { 135 if (!methodEntry.isConstructor()) {
124 methodImplementations.put(methodEntry.getParent().getFullName(), methodEntry); 136 methodImplementations.put(methodEntry.getParent().getFullName(), methodEntry);
@@ -176,6 +188,10 @@ public class JarIndex implements JarIndexer {
176 return entryResolver; 188 return entryResolver;
177 } 189 }
178 190
191 public Map<ClassEntry, List<ParentedEntry>> getChildrenByClass() {
192 return this.childrenByClass;
193 }
194
179 public boolean isIndexed(String internalName) { 195 public boolean isIndexed(String internalName) {
180 return indexedClasses.contains(internalName); 196 return indexedClasses.contains(internalName);
181 } 197 }
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
index a7dccfc..6a1b82f 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
@@ -235,14 +235,14 @@ public class TypeDescriptor implements Translatable {
235 } 235 }
236 236
237 public enum Primitive { 237 public enum Primitive {
238 BYTE('B'), 238 BYTE('B', "byte"),
239 CHARACTER('C'), 239 CHARACTER('C', "char"),
240 SHORT('S'), 240 SHORT('S', "short"),
241 INTEGER('I'), 241 INTEGER('I', "int"),
242 LONG('J'), 242 LONG('J', "long"),
243 FLOAT('F'), 243 FLOAT('F', "float"),
244 DOUBLE('D'), 244 DOUBLE('D', "double"),
245 BOOLEAN('Z'); 245 BOOLEAN('Z', "boolean");
246 246
247 private static final Map<Character, Primitive> lookup; 247 private static final Map<Character, Primitive> lookup;
248 248
@@ -254,9 +254,11 @@ public class TypeDescriptor implements Translatable {
254 } 254 }
255 255
256 private char code; 256 private char code;
257 private String keyword;
257 258
258 Primitive(char code) { 259 Primitive(char code, String keyword) {
259 this.code = code; 260 this.code = code;
261 this.keyword = keyword;
260 } 262 }
261 263
262 public static Primitive get(char code) { 264 public static Primitive get(char code) {
@@ -266,5 +268,12 @@ public class TypeDescriptor implements Translatable {
266 public char getCode() { 268 public char getCode() {
267 return this.code; 269 return this.code;
268 } 270 }
271
272 /**
273 * Returns the Java keyword corresponding to this primitive.
274 */
275 public String getKeyword() {
276 return this.keyword;
277 }
269 } 278 }
270} 279}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
index 4a50021..b4a22f1 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
@@ -134,6 +134,9 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
134 return name; 134 return name;
135 } 135 }
136 136
137 /**
138 * Returns whether this class entry has a parent, and therefore is an inner class.
139 */
137 public boolean isInnerClass() { 140 public boolean isInnerClass() {
138 return parent != null; 141 return parent != null;
139 } 142 }
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
index ff392fe..6fd412a 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
@@ -29,6 +29,13 @@ public interface Entry<P extends Entry<?>> extends Translatable {
29 return getName(); 29 return getName();
30 } 30 }
31 31
32 /**
33 * Returns the parent entry of this entry.
34 *
35 * <p>The parent entry should be a {@linkplain MethodEntry method} for local variables,
36 * a {@linkplain ClassEntry class} for methods, fields and inner classes, and {@code null}
37 * for other classes.</p>
38 */
32 @Nullable 39 @Nullable
33 P getParent(); 40 P getParent();
34 41
diff --git a/enigma/src/main/resources/lang/en_us.json b/enigma/src/main/resources/lang/en_us.json
index 9db4e1f..8195bb1 100644
--- a/enigma/src/main/resources/lang/en_us.json
+++ b/enigma/src/main/resources/lang/en_us.json
@@ -101,6 +101,8 @@
101 "info_panel.identifier.index": "Index", 101 "info_panel.identifier.index": "Index",
102 "info_panel.editor.class.decompiling": "(decompiling...)", 102 "info_panel.editor.class.decompiling": "(decompiling...)",
103 "info_panel.editor.class.not_found": "Unable to find class:", 103 "info_panel.editor.class.not_found": "Unable to find class:",
104 "info_panel.tree.structure": "Structure",
105 "info_panel.tree.structure.hide_deobfuscated": "Hide deobfuscated members",
104 "info_panel.tree.inheritance": "Inheritance", 106 "info_panel.tree.inheritance": "Inheritance",
105 "info_panel.tree.implementations": "Implementations", 107 "info_panel.tree.implementations": "Implementations",
106 "info_panel.tree.calls": "Call Graph", 108 "info_panel.tree.calls": "Call Graph",
diff --git a/enigma/src/main/resources/lang/fr_fr.json b/enigma/src/main/resources/lang/fr_fr.json
index 127b9c8..43bea4d 100644
--- a/enigma/src/main/resources/lang/fr_fr.json
+++ b/enigma/src/main/resources/lang/fr_fr.json
@@ -101,6 +101,8 @@
101 "info_panel.identifier.index": "Index", 101 "info_panel.identifier.index": "Index",
102 "info_panel.editor.class.decompiling": "(décompilation...)", 102 "info_panel.editor.class.decompiling": "(décompilation...)",
103 "info_panel.editor.class.not_found": "Impossible de trouver la classe :", 103 "info_panel.editor.class.not_found": "Impossible de trouver la classe :",
104 "info_panel.tree.structure": "Structure",
105 "info_panel.tree.structure.hide_deobfuscated": "Masquer les membres déobfusqués",
104 "info_panel.tree.inheritance": "Héritage", 106 "info_panel.tree.inheritance": "Héritage",
105 "info_panel.tree.implementations": "Implémentations", 107 "info_panel.tree.implementations": "Implémentations",
106 "info_panel.tree.calls": "Graphique des appels", 108 "info_panel.tree.calls": "Graphique des appels",