summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java2
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java4
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java63
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java21
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java54
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java59
-rw-r--r--enigma/src/main/resources/lang/en_us.json14
-rw-r--r--enigma/src/main/resources/lang/fr_fr.json14
-rw-r--r--enigma/src/main/resources/lang/ja_jp.json1
9 files changed, 197 insertions, 35 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 8d4fb5be..60c535f5 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -622,7 +622,7 @@ public class Gui implements LanguageChangeListener {
622 this.structurePanel.getSortingPanel().setVisible(true); 622 this.structurePanel.getSortingPanel().setVisible(true);
623 623
624 // get the class structure 624 // get the class structure
625 StructureTreeNode node = this.controller.getClassStructure(classEntry, this.structurePanel.shouldHideDeobfuscated()); 625 StructureTreeNode node = this.controller.getClassStructure(classEntry, this.structurePanel.getOptions());
626 626
627 // show the tree at the root 627 // show the tree at the root
628 TreePath path = getPathToRoot(node); 628 TreePath path = getPathToRoot(node);
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 aeee242f..e6f7b832 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -396,9 +396,9 @@ public class GuiController implements ClientPacketHandler {
396 chp.invalidateMapped(); 396 chp.invalidateMapped();
397 } 397 }
398 398
399 public StructureTreeNode getClassStructure(ClassEntry entry, boolean hideDeobfuscated) { 399 public StructureTreeNode getClassStructure(ClassEntry entry, StructureTreeOptions options) {
400 StructureTreeNode rootNode = new StructureTreeNode(this.project, entry, entry); 400 StructureTreeNode rootNode = new StructureTreeNode(this.project, entry, entry);
401 rootNode.load(this.project, hideDeobfuscated); 401 rootNode.load(this.project, options);
402 return rootNode; 402 return rootNode;
403 } 403 }
404 404
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
index d6f7e5a7..1bff9a98 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java
@@ -1,7 +1,10 @@
1package cuchaz.enigma.gui.panels; 1package cuchaz.enigma.gui.panels;
2 2
3import cuchaz.enigma.analysis.StructureTreeOptions;
3import cuchaz.enigma.analysis.StructureTreeNode; 4import cuchaz.enigma.analysis.StructureTreeNode;
4import cuchaz.enigma.gui.Gui; 5import cuchaz.enigma.gui.Gui;
6import cuchaz.enigma.gui.renderer.StructureOptionListCellRenderer;
7import cuchaz.enigma.gui.util.GridBagConstraintsBuilder;
5import cuchaz.enigma.gui.util.GuiUtil; 8import cuchaz.enigma.gui.util.GuiUtil;
6import cuchaz.enigma.gui.util.SingleTreeSelectionModel; 9import cuchaz.enigma.gui.util.SingleTreeSelectionModel;
7import cuchaz.enigma.translation.representation.entry.ClassEntry; 10import cuchaz.enigma.translation.representation.entry.ClassEntry;
@@ -18,17 +21,41 @@ import java.awt.event.MouseAdapter;
18import java.awt.event.MouseEvent; 21import java.awt.event.MouseEvent;
19 22
20public class StructurePanel extends JPanel { 23public class StructurePanel extends JPanel {
21 private JPanel sortingPanel; 24 private final JPanel optionsPanel;
22 private JCheckBox hideDeobfuscated;
23 25
24 private JTree structureTree; 26 private final JLabel obfuscationVisibilityLabel = new JLabel();
27 private final JLabel documentationVisibilityLabel = new JLabel();
28 private final JLabel sortingOrderLabel = new JLabel();
29
30 private final JComboBox<StructureTreeOptions.ObfuscationVisibility> obfuscationVisibility;
31 private final JComboBox<StructureTreeOptions.DocumentationVisibility> documentationVisibility;
32 private final JComboBox<StructureTreeOptions.SortingOrder> sortingOrder;
33
34 private final JTree structureTree;
25 35
26 public StructurePanel(Gui gui) { 36 public StructurePanel(Gui gui) {
27 this.sortingPanel = new JPanel(); 37 this.optionsPanel = new JPanel(new GridBagLayout());
28 this.hideDeobfuscated = new JCheckBox(I18n.translate("info_panel.tree.structure.hide_deobfuscated")); 38 this.optionsPanel.setVisible(false);
29 this.hideDeobfuscated.addActionListener(event -> gui.showStructure(gui.getActiveEditor())); 39
30 this.sortingPanel.add(this.hideDeobfuscated); 40 GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(5).fill(GridBagConstraints.HORIZONTAL);
31 this.sortingPanel.setVisible(false); 41
42 this.optionsPanel.add(this.obfuscationVisibilityLabel, cb.pos(0, 0).build());
43 this.obfuscationVisibility = new JComboBox<>(StructureTreeOptions.ObfuscationVisibility.values());
44 this.obfuscationVisibility.setRenderer(new StructureOptionListCellRenderer());
45 this.obfuscationVisibility.addActionListener(event -> gui.showStructure(gui.getActiveEditor()));
46 this.optionsPanel.add(this.obfuscationVisibility, cb.pos(1, 0).build());
47
48 this.optionsPanel.add(this.documentationVisibilityLabel, cb.pos(0, 1).build());
49 this.documentationVisibility = new JComboBox<>(StructureTreeOptions.DocumentationVisibility.values());
50 this.documentationVisibility.setRenderer(new StructureOptionListCellRenderer());
51 this.documentationVisibility.addActionListener(event -> gui.showStructure(gui.getActiveEditor()));
52 this.optionsPanel.add(this.documentationVisibility, cb.pos(1, 1).build());
53
54 this.optionsPanel.add(this.sortingOrderLabel, cb.pos(0, 2).build());
55 this.sortingOrder = new JComboBox<>(StructureTreeOptions.SortingOrder.values());
56 this.sortingOrder.setRenderer(new StructureOptionListCellRenderer());
57 this.sortingOrder.addActionListener(event -> gui.showStructure(gui.getActiveEditor()));
58 this.optionsPanel.add(this.sortingOrder, cb.pos(1, 2).build());
32 59
33 this.structureTree = new JTree(); 60 this.structureTree = new JTree();
34 this.structureTree.setModel(null); 61 this.structureTree.setModel(null);
@@ -53,20 +80,26 @@ public class StructurePanel extends JPanel {
53 } 80 }
54 }); 81 });
55 82
83 this.retranslateUi();
84
56 this.setLayout(new BorderLayout()); 85 this.setLayout(new BorderLayout());
57 this.add(this.sortingPanel, BorderLayout.NORTH); 86 this.add(this.optionsPanel, BorderLayout.NORTH);
58 this.add(new JScrollPane(this.structureTree)); 87 this.add(new JScrollPane(this.structureTree));
59 } 88 }
60 89
61 public JPanel getSortingPanel() { 90 public JPanel getSortingPanel() {
62 return this.sortingPanel; 91 return this.optionsPanel;
63 } 92 }
64 93
65 /** 94 /**
66 * Returns whether the "Hide Deobfuscated" option of this structure panel is selected. 95 * Creates and returns the options of this structure panel.
67 */ 96 */
68 public boolean shouldHideDeobfuscated() { 97 public StructureTreeOptions getOptions() {
69 return this.hideDeobfuscated.isSelected(); 98 return new StructureTreeOptions(
99 (StructureTreeOptions.ObfuscationVisibility) this.obfuscationVisibility.getSelectedItem(),
100 (StructureTreeOptions.DocumentationVisibility) this.documentationVisibility.getSelectedItem(),
101 (StructureTreeOptions.SortingOrder) this.sortingOrder.getSelectedItem()
102 );
70 } 103 }
71 104
72 public JTree getStructureTree() { 105 public JTree getStructureTree() {
@@ -74,7 +107,9 @@ public class StructurePanel extends JPanel {
74 } 107 }
75 108
76 public void retranslateUi() { 109 public void retranslateUi() {
77 this.hideDeobfuscated.setText(I18n.translate("info_panel.tree.structure.hide_deobfuscated")); 110 this.obfuscationVisibilityLabel.setText(I18n.translate("structure.options.obfuscation"));
111 this.documentationVisibilityLabel.setText(I18n.translate("structure.options.documentation"));
112 this.sortingOrderLabel.setText(I18n.translate("structure.options.sorting"));
78 } 113 }
79 114
80 class StructureTreeCellRenderer extends DefaultTreeCellRenderer { 115 class StructureTreeCellRenderer extends DefaultTreeCellRenderer {
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java
new file mode 100644
index 00000000..f9a1cae6
--- /dev/null
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java
@@ -0,0 +1,21 @@
1package cuchaz.enigma.gui.renderer;
2
3import cuchaz.enigma.analysis.StructureTreeOptions;
4import cuchaz.enigma.utils.I18n;
5
6import javax.swing.*;
7import java.awt.*;
8
9public class StructureOptionListCellRenderer extends DefaultListCellRenderer {
10
11 @Override
12 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
13 Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
14
15 if (value instanceof StructureTreeOptions.Option option) {
16 this.setText(I18n.translate(option.getTranslationKey()));
17 }
18
19 return c;
20 }
21}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
index b4343c10..aea76180 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
@@ -10,7 +10,9 @@ import cuchaz.enigma.translation.representation.entry.*;
10 10
11import javax.swing.tree.DefaultMutableTreeNode; 11import javax.swing.tree.DefaultMutableTreeNode;
12import java.util.ArrayList; 12import java.util.ArrayList;
13import java.util.Comparator;
13import java.util.List; 14import java.util.List;
15import java.util.stream.Stream;
14 16
15public class StructureTreeNode extends DefaultMutableTreeNode { 17public class StructureTreeNode extends DefaultMutableTreeNode {
16 private final List<NameProposalService> nameProposalServices; 18 private final List<NameProposalService> nameProposalServices;
@@ -32,25 +34,47 @@ public class StructureTreeNode extends DefaultMutableTreeNode {
32 return this.entry; 34 return this.entry;
33 } 35 }
34 36
35 public void load(EnigmaProject project, boolean hideDeobfuscated) { 37 public void load(EnigmaProject project, StructureTreeOptions options) {
36 List<ParentedEntry> children = project.getJarIndex().getChildrenByClass().get(this.parentEntry); 38 Stream<ParentedEntry> children = project.getJarIndex().getChildrenByClass().get(this.parentEntry).stream();
37 39
38 for (ParentedEntry child : children) { 40 children = switch (options.obfuscationVisibility()) {
41 case ALL -> children;
42 case OBFUSCATED -> children
43 // remove deobfuscated members if only obfuscated, unless it's an inner class
44 .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e)))
45 // keep constructor methods if the class is obfuscated
46 .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent()));
47 case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry)
48 || (!project.isObfuscated(e) && project.isRenamable(e))
49 // keep constructor methods if the class is deobfuscated
50 || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent()));
51 };
52
53 children = switch (options.documentationVisibility()) {
54 case ALL -> children;
55 // TODO remove EntryRemapper.deobfuscate() calls when javadocs will no longer be tied to deobfuscation
56 case DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() != null && !project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
57 case NON_DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() == null || project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
58 };
59
60 children = switch (options.sortingOrder()) {
61 case DEFAULT -> children;
62 case A_Z -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor())
63 // compare the class name when the entry is a constructor
64 ? project.getMapper().deobfuscate(e.getParent()).getSimpleName().toLowerCase()
65 : project.getMapper().deobfuscate(e).getSimpleName().toLowerCase()));
66 case Z_A -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor())
67 ? project.getMapper().deobfuscate(((ParentedEntry<?>) e).getParent()).getSimpleName().toLowerCase()
68 : project.getMapper().deobfuscate((ParentedEntry<?>) e).getSimpleName().toLowerCase())
69 .reversed());
70 };
71
72 for (ParentedEntry<?> child : children.toList()) {
39 StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child); 73 StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child);
40 74
41 if (child instanceof ClassEntry) { 75 if (child instanceof ClassEntry) {
42 childNode = new StructureTreeNode(project, (ClassEntry) child, child); 76 childNode = new StructureTreeNode(project, (ClassEntry) child, child);
43 childNode.load(project, hideDeobfuscated); 77 childNode.load(project, options);
44 }
45
46 // don't add deobfuscated members if hideDeobfuscated is true, unless it's an inner class
47 if (hideDeobfuscated && !project.isObfuscated(child) && !(child instanceof ClassEntry)) {
48 continue;
49 }
50
51 // don't add constructor methods if hideDeobfuscated is true
52 if (hideDeobfuscated && (child instanceof MethodEntry method) && method.isConstructor()) {
53 continue;
54 } 78 }
55 79
56 this.add(childNode); 80 this.add(childNode);
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
new file mode 100644
index 00000000..cfc80b4a
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
@@ -0,0 +1,59 @@
1package cuchaz.enigma.analysis;
2
3public record StructureTreeOptions(
4 ObfuscationVisibility obfuscationVisibility,
5 DocumentationVisibility documentationVisibility,
6 SortingOrder sortingOrder) {
7
8 public enum ObfuscationVisibility implements Option {
9 ALL("structure.options.obfuscation.all"),
10 OBFUSCATED("structure.options.obfuscation.obfuscated"),
11 DEOBFUSCATED("structure.options.obfuscation.deobfuscated");
12
13 private final String translationKey;
14
15 ObfuscationVisibility(String translationKey) {
16 this.translationKey = translationKey;
17 }
18
19 public String getTranslationKey() {
20 return this.translationKey;
21 }
22 }
23
24 public enum DocumentationVisibility implements Option {
25 ALL("structure.options.documentation.all"),
26 DOCUMENTED("structure.options.documentation.documented"),
27 NON_DOCUMENTED("structure.options.documentation.non_documented");
28
29 private final String translationKey;
30
31 DocumentationVisibility(String translationKey) {
32 this.translationKey = translationKey;
33 }
34
35 public String getTranslationKey() {
36 return this.translationKey;
37 }
38 }
39
40 public enum SortingOrder implements Option {
41 DEFAULT("structure.options.sorting.default"),
42 A_Z("structure.options.sorting.a_z"),
43 Z_A("structure.options.sorting.z_a");
44
45 private final String translationKey;
46
47 SortingOrder(String translationKey) {
48 this.translationKey = translationKey;
49 }
50
51 public String getTranslationKey() {
52 return this.translationKey;
53 }
54 }
55
56 public interface Option {
57 String getTranslationKey();
58 }
59}
diff --git a/enigma/src/main/resources/lang/en_us.json b/enigma/src/main/resources/lang/en_us.json
index 57b2ca8f..35a4d93e 100644
--- a/enigma/src/main/resources/lang/en_us.json
+++ b/enigma/src/main/resources/lang/en_us.json
@@ -106,13 +106,25 @@
106 "info_panel.editor.class.decompiling": "(decompiling...)", 106 "info_panel.editor.class.decompiling": "(decompiling...)",
107 "info_panel.editor.class.not_found": "Unable to find class:", 107 "info_panel.editor.class.not_found": "Unable to find class:",
108 "info_panel.tree.structure": "Structure", 108 "info_panel.tree.structure": "Structure",
109 "info_panel.tree.structure.hide_deobfuscated": "Hide deobfuscated members",
110 "info_panel.tree.inheritance": "Inheritance", 109 "info_panel.tree.inheritance": "Inheritance",
111 "info_panel.tree.implementations": "Implementations", 110 "info_panel.tree.implementations": "Implementations",
112 "info_panel.tree.calls": "Call Graph", 111 "info_panel.tree.calls": "Call Graph",
113 112
114 "popup.copied": "Copied!", 113 "popup.copied": "Copied!",
115 114
115 "structure.options.obfuscation": "Obfuscation Visibility",
116 "structure.options.obfuscation.all": "All",
117 "structure.options.obfuscation.obfuscated": "Only obfuscated",
118 "structure.options.obfuscation.deobfuscated": "Only deobfuscated",
119 "structure.options.documentation": "Documentation Visibility",
120 "structure.options.documentation.all": "All",
121 "structure.options.documentation.documented": "Only documented",
122 "structure.options.documentation.non_documented": "Only non documented",
123 "structure.options.sorting": "Sorting Order",
124 "structure.options.sorting.default": "Default",
125 "structure.options.sorting.a_z": "A to Z",
126 "structure.options.sorting.z_a": "Z to A",
127
116 "log_panel.messages": "Messages", 128 "log_panel.messages": "Messages",
117 "log_panel.users": "Users", 129 "log_panel.users": "Users",
118 130
diff --git a/enigma/src/main/resources/lang/fr_fr.json b/enigma/src/main/resources/lang/fr_fr.json
index 5c46c87a..ea1a20f6 100644
--- a/enigma/src/main/resources/lang/fr_fr.json
+++ b/enigma/src/main/resources/lang/fr_fr.json
@@ -106,13 +106,25 @@
106 "info_panel.editor.class.decompiling": "(décompilation...)", 106 "info_panel.editor.class.decompiling": "(décompilation...)",
107 "info_panel.editor.class.not_found": "Impossible de trouver la classe :", 107 "info_panel.editor.class.not_found": "Impossible de trouver la classe :",
108 "info_panel.tree.structure": "Structure", 108 "info_panel.tree.structure": "Structure",
109 "info_panel.tree.structure.hide_deobfuscated": "Masquer les membres déobfusqués",
110 "info_panel.tree.inheritance": "Héritage", 109 "info_panel.tree.inheritance": "Héritage",
111 "info_panel.tree.implementations": "Implémentations", 110 "info_panel.tree.implementations": "Implémentations",
112 "info_panel.tree.calls": "Graphique des appels", 111 "info_panel.tree.calls": "Graphique des appels",
113 112
114 "popup.copied": "Copié !", 113 "popup.copied": "Copié !",
115 114
115 "structure.options.obfuscation": "Visibilité de l'obfuscation",
116 "structure.options.obfuscation.all": "Tous",
117 "structure.options.obfuscation.obfuscated": "Seulement obfusqués",
118 "structure.options.obfuscation.deobfuscated": "Seulement déobfusqués",
119 "structure.options.documentation": "Visibilité de la documentation",
120 "structure.options.documentation.all": "Tous",
121 "structure.options.documentation.documented": "Seulement documentés",
122 "structure.options.documentation.non_documented": "Seulement non documentés",
123 "structure.options.sorting": "Ordre de tri",
124 "structure.options.sorting.default": "Par défaut",
125 "structure.options.sorting.a_z": "A à Z",
126 "structure.options.sorting.z_a": "Z à A",
127
116 "log_panel.messages": "Messages", 128 "log_panel.messages": "Messages",
117 "log_panel.users": "Utilisateurs", 129 "log_panel.users": "Utilisateurs",
118 130
diff --git a/enigma/src/main/resources/lang/ja_jp.json b/enigma/src/main/resources/lang/ja_jp.json
index 0ff162a1..9399e172 100644
--- a/enigma/src/main/resources/lang/ja_jp.json
+++ b/enigma/src/main/resources/lang/ja_jp.json
@@ -102,7 +102,6 @@
102 "info_panel.editor.class.decompiling": "(デコンパイル中...)", 102 "info_panel.editor.class.decompiling": "(デコンパイル中...)",
103 "info_panel.editor.class.not_found": "クラスが見つけられません:", 103 "info_panel.editor.class.not_found": "クラスが見つけられません:",
104 "info_panel.tree.structure": "構造", 104 "info_panel.tree.structure": "構造",
105 "info_panel.tree.structure.hide_deobfuscated": "難読化解除されたメンバを隠す",
106 "info_panel.tree.inheritance": "継承", 105 "info_panel.tree.inheritance": "継承",
107 "info_panel.tree.implementations": "実装", 106 "info_panel.tree.implementations": "実装",
108 "info_panel.tree.calls": "呼び出し関係", 107 "info_panel.tree.calls": "呼び出し関係",