summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/gui/Gui.java
diff options
context:
space:
mode:
authorGravatar Thog2017-03-08 08:17:04 +0100
committerGravatar Thog2017-03-08 08:17:04 +0100
commit6e464ea251cab63c776ece0b2a356f1498ffa294 (patch)
tree5ed30c03f5ac4cd2d6877874f5ede576049954f7 /src/main/java/cuchaz/enigma/gui/Gui.java
parentDrop unix case style and implement hashCode when equals is overrided (diff)
downloadenigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.gz
enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.xz
enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.zip
Follow Fabric guidelines
Diffstat (limited to 'src/main/java/cuchaz/enigma/gui/Gui.java')
-rw-r--r--src/main/java/cuchaz/enigma/gui/Gui.java1594
1 files changed, 787 insertions, 807 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java
index 7cb494f..9f8d6fc 100644
--- a/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -8,6 +8,7 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
12 13
13import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
@@ -54,811 +55,790 @@ import java.util.function.Function;
54 55
55public class Gui { 56public class Gui {
56 57
57 private GuiController controller; 58 public final PopupMenuBar popupMenu;
58 59 private final PanelObf obfPanel;
59 private final PanelObf obfPanel; 60 private final PanelDeobf deobfPanel;
60 private final PanelDeobf deobfPanel; 61
61 62 private final MenuBar menuBar;
62 private final MenuBar menuBar; 63 // state
63 public final PopupMenuBar popupMenu; 64 public EntryReference<Entry, Entry> reference;
64 65 public JFileChooser jarFileChooser;
65 private JFrame frame; 66 public JFileChooser enigmaMappingsFileChooser;
66 private PanelEditor editor; 67 public JFileChooser exportSourceFileChooser;
67 private JPanel classesPanel; 68 public JFileChooser exportJarFileChooser;
68 private JSplitPane splitClasses; 69 private GuiController controller;
69 private PanelIdentifier infoPanel; 70 private JFrame frame;
70 private ObfuscatedHighlightPainter obfuscatedHighlightPainter; 71 private PanelEditor editor;
71 private DeobfuscatedHighlightPainter deobfuscatedHighlightPainter; 72 private JPanel classesPanel;
72 private OtherHighlightPainter otherHighlightPainter; 73 private JSplitPane splitClasses;
73 private SelectionHighlightPainter selectionHighlightPainter; 74 private PanelIdentifier infoPanel;
74 private JTree inheritanceTree; 75 private ObfuscatedHighlightPainter obfuscatedHighlightPainter;
75 private JTree implementationsTree; 76 private DeobfuscatedHighlightPainter deobfuscatedHighlightPainter;
76 private JTree callsTree; 77 private OtherHighlightPainter otherHighlightPainter;
77 private JList<Token> tokens; 78 private SelectionHighlightPainter selectionHighlightPainter;
78 private JTabbedPane tabs; 79 private JTree inheritanceTree;
79 80 private JTree implementationsTree;
80 // state 81 private JTree callsTree;
81 public EntryReference<Entry, Entry> reference; 82 private JList<Token> tokens;
82 83 private JTabbedPane tabs;
83 public JFileChooser jarFileChooser; 84
84 public JFileChooser enigmaMappingsFileChooser; 85 public Gui() {
85 86
86 public JFileChooser exportSourceFileChooser; 87 // init frame
87 public JFileChooser exportJarFileChooser; 88 this.frame = new JFrame(Constants.NAME);
88 89 final Container pane = this.frame.getContentPane();
89 public Gui() { 90 pane.setLayout(new BorderLayout());
90 91
91 // init frame 92 if (Boolean.parseBoolean(System.getProperty("enigma.catchExceptions", "true"))) {
92 this.frame = new JFrame(Constants.NAME); 93 // install a global exception handler to the event thread
93 final Container pane = this.frame.getContentPane(); 94 CrashDialog.init(this.frame);
94 pane.setLayout(new BorderLayout()); 95 Thread.setDefaultUncaughtExceptionHandler((thread, t) -> {
95 96 t.printStackTrace(System.err);
96 if (Boolean.parseBoolean(System.getProperty("enigma.catchExceptions", "true"))) { 97 if (!ExceptionIgnorer.shouldIgnore(t)) {
97 // install a global exception handler to the event thread 98 CrashDialog.show(t);
98 CrashDialog.init(this.frame); 99 }
99 Thread.setDefaultUncaughtExceptionHandler((thread, t) -> { 100 });
100 t.printStackTrace(System.err); 101 }
101 if (!ExceptionIgnorer.shouldIgnore(t)) { 102
102 CrashDialog.show(t); 103 this.controller = new GuiController(this);
103 } 104
104 }); 105 // init file choosers
105 } 106 this.jarFileChooser = new FileChooserFile();
106 107
107 this.controller = new GuiController(this); 108 this.enigmaMappingsFileChooser = new FileChooserAny();
108 109 this.exportSourceFileChooser = new FileChooserFolder();
109 // init file choosers 110 this.exportJarFileChooser = new FileChooserFile();
110 this.jarFileChooser = new FileChooserFile(); 111
111 112 this.obfPanel = new PanelObf(this);
112 113 this.deobfPanel = new PanelDeobf(this);
113 this.enigmaMappingsFileChooser = new FileChooserAny(); 114
114 this.exportSourceFileChooser = new FileChooserFolder(); 115 // set up classes panel (don't add the splitter yet)
115 this.exportJarFileChooser = new FileChooserFile(); 116 splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, this.obfPanel, this.deobfPanel);
116 117 splitClasses.setResizeWeight(0.3);
117 this.obfPanel = new PanelObf(this); 118 this.classesPanel = new JPanel();
118 this.deobfPanel = new PanelDeobf(this); 119 this.classesPanel.setLayout(new BorderLayout());
119 120 this.classesPanel.setPreferredSize(new Dimension(250, 0));
120 // set up classes panel (don't add the splitter yet) 121
121 splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, this.obfPanel, this.deobfPanel); 122 // init info panel
122 splitClasses.setResizeWeight(0.3); 123 infoPanel = new PanelIdentifier(this);
123 this.classesPanel = new JPanel(); 124 infoPanel.clearReference();
124 this.classesPanel.setLayout(new BorderLayout()); 125
125 this.classesPanel.setPreferredSize(new Dimension(250, 0)); 126 // init editor
126 127 DefaultSyntaxKit.initKit();
127 // init info panel 128 obfuscatedHighlightPainter = new ObfuscatedHighlightPainter();
128 infoPanel = new PanelIdentifier(this); 129 deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter();
129 infoPanel.clearReference(); 130 otherHighlightPainter = new OtherHighlightPainter();
130 131 selectionHighlightPainter = new SelectionHighlightPainter();
131 // init editor 132 this.editor = new PanelEditor(this);
132 DefaultSyntaxKit.initKit(); 133 JScrollPane sourceScroller = new JScrollPane(this.editor);
133 obfuscatedHighlightPainter = new ObfuscatedHighlightPainter(); 134 this.editor.setContentType("text/java");
134 deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter(); 135 DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit();
135 otherHighlightPainter = new OtherHighlightPainter(); 136 kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker");
136 selectionHighlightPainter = new SelectionHighlightPainter(); 137
137 this.editor = new PanelEditor(this); 138 // init editor popup menu
138 JScrollPane sourceScroller = new JScrollPane(this.editor); 139 this.popupMenu = new PopupMenuBar(this);
139 this.editor.setContentType("text/java"); 140 this.editor.setComponentPopupMenu(this.popupMenu);
140 DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); 141
141 kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker"); 142 // init inheritance panel
142 143 inheritanceTree = new JTree();
143 // init editor popup menu 144 inheritanceTree.setModel(null);
144 this.popupMenu = new PopupMenuBar(this); 145 inheritanceTree.addMouseListener(new MouseAdapter() {
145 this.editor.setComponentPopupMenu(this.popupMenu); 146 @Override
146 147 public void mouseClicked(MouseEvent event) {
147 // init inheritance panel 148 if (event.getClickCount() == 2) {
148 inheritanceTree = new JTree(); 149 // get the selected node
149 inheritanceTree.setModel(null); 150 TreePath path = inheritanceTree.getSelectionPath();
150 inheritanceTree.addMouseListener(new MouseAdapter() { 151 if (path == null) {
151 @Override 152 return;
152 public void mouseClicked(MouseEvent event) { 153 }
153 if (event.getClickCount() == 2) { 154
154 // get the selected node 155 Object node = path.getLastPathComponent();
155 TreePath path = inheritanceTree.getSelectionPath(); 156 if (node instanceof ClassInheritanceTreeNode) {
156 if (path == null) { 157 ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode) node;
157 return; 158 navigateTo(new ClassEntry(classNode.getObfClassName()));
158 } 159 } else if (node instanceof MethodInheritanceTreeNode) {
159 160 MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode) node;
160 Object node = path.getLastPathComponent(); 161 if (methodNode.isImplemented()) {
161 if (node instanceof ClassInheritanceTreeNode) { 162 navigateTo(methodNode.getMethodEntry());
162 ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode) node; 163 }
163 navigateTo(new ClassEntry(classNode.getObfClassName())); 164 }
164 } else if (node instanceof MethodInheritanceTreeNode) { 165 }
165 MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode) node; 166 }
166 if (methodNode.isImplemented()) { 167 });
167 navigateTo(methodNode.getMethodEntry()); 168 JPanel inheritancePanel = new JPanel();
168 } 169 inheritancePanel.setLayout(new BorderLayout());
169 } 170 inheritancePanel.add(new JScrollPane(inheritanceTree));
170 } 171
171 } 172 // init implementations panel
172 }); 173 implementationsTree = new JTree();
173 JPanel inheritancePanel = new JPanel(); 174 implementationsTree.setModel(null);
174 inheritancePanel.setLayout(new BorderLayout()); 175 implementationsTree.addMouseListener(new MouseAdapter() {
175 inheritancePanel.add(new JScrollPane(inheritanceTree)); 176 @Override
176 177 public void mouseClicked(MouseEvent event) {
177 // init implementations panel 178 if (event.getClickCount() == 2) {
178 implementationsTree = new JTree(); 179 // get the selected node
179 implementationsTree.setModel(null); 180 TreePath path = implementationsTree.getSelectionPath();
180 implementationsTree.addMouseListener(new MouseAdapter() { 181 if (path == null) {
181 @Override 182 return;
182 public void mouseClicked(MouseEvent event) { 183 }
183 if (event.getClickCount() == 2) { 184
184 // get the selected node 185 Object node = path.getLastPathComponent();
185 TreePath path = implementationsTree.getSelectionPath(); 186 if (node instanceof ClassImplementationsTreeNode) {
186 if (path == null) { 187 ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode) node;
187 return; 188 navigateTo(classNode.getClassEntry());
188 } 189 } else if (node instanceof MethodImplementationsTreeNode) {
189 190 MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode) node;
190 Object node = path.getLastPathComponent(); 191 navigateTo(methodNode.getMethodEntry());
191 if (node instanceof ClassImplementationsTreeNode) { 192 }
192 ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode) node; 193 }
193 navigateTo(classNode.getClassEntry()); 194 }
194 } else if (node instanceof MethodImplementationsTreeNode) { 195 });
195 MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode) node; 196 JPanel implementationsPanel = new JPanel();
196 navigateTo(methodNode.getMethodEntry()); 197 implementationsPanel.setLayout(new BorderLayout());
197 } 198 implementationsPanel.add(new JScrollPane(implementationsTree));
198 } 199
199 } 200 // init call panel
200 }); 201 callsTree = new JTree();
201 JPanel implementationsPanel = new JPanel(); 202 callsTree.setModel(null);
202 implementationsPanel.setLayout(new BorderLayout()); 203 callsTree.addMouseListener(new MouseAdapter() {
203 implementationsPanel.add(new JScrollPane(implementationsTree)); 204 @SuppressWarnings("unchecked")
204 205 @Override
205 // init call panel 206 public void mouseClicked(MouseEvent event) {
206 callsTree = new JTree(); 207 if (event.getClickCount() == 2) {
207 callsTree.setModel(null); 208 // get the selected node
208 callsTree.addMouseListener(new MouseAdapter() { 209 TreePath path = callsTree.getSelectionPath();
209 @SuppressWarnings("unchecked") 210 if (path == null) {
210 @Override 211 return;
211 public void mouseClicked(MouseEvent event) { 212 }
212 if (event.getClickCount() == 2) { 213
213 // get the selected node 214 Object node = path.getLastPathComponent();
214 TreePath path = callsTree.getSelectionPath(); 215 if (node instanceof ReferenceTreeNode) {
215 if (path == null) { 216 ReferenceTreeNode<Entry, Entry> referenceNode = ((ReferenceTreeNode<Entry, Entry>) node);
216 return; 217 if (referenceNode.getReference() != null) {
217 } 218 navigateTo(referenceNode.getReference());
218 219 } else {
219 Object node = path.getLastPathComponent(); 220 navigateTo(referenceNode.getEntry());
220 if (node instanceof ReferenceTreeNode) { 221 }
221 ReferenceTreeNode<Entry, Entry> referenceNode = ((ReferenceTreeNode<Entry, Entry>) node); 222 }
222 if (referenceNode.getReference() != null) { 223 }
223 navigateTo(referenceNode.getReference()); 224 }
224 } else { 225 });
225 navigateTo(referenceNode.getEntry()); 226 tokens = new JList<>();
226 } 227 tokens.setCellRenderer(new TokenListCellRenderer(this.controller));
227 } 228 tokens.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
228 } 229 tokens.setLayoutOrientation(JList.VERTICAL);
229 } 230 tokens.addMouseListener(new MouseAdapter() {
230 }); 231 @Override
231 tokens = new JList<>(); 232 public void mouseClicked(MouseEvent event) {
232 tokens.setCellRenderer(new TokenListCellRenderer(this.controller)); 233 if (event.getClickCount() == 2) {
233 tokens.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 234 Token selected = tokens.getSelectedValue();
234 tokens.setLayoutOrientation(JList.VERTICAL); 235 if (selected != null) {
235 tokens.addMouseListener(new MouseAdapter() { 236 showToken(selected);
236 @Override 237 }
237 public void mouseClicked(MouseEvent event) { 238 }
238 if (event.getClickCount() == 2) { 239 }
239 Token selected = tokens.getSelectedValue(); 240 });
240 if (selected != null) { 241 tokens.setPreferredSize(new Dimension(0, 200));
241 showToken(selected); 242 tokens.setMinimumSize(new Dimension(0, 200));
242 } 243 JSplitPane callPanel = new JSplitPane(
243 } 244 JSplitPane.VERTICAL_SPLIT,
244 } 245 true,
245 }); 246 new JScrollPane(callsTree),
246 tokens.setPreferredSize(new Dimension(0, 200)); 247 new JScrollPane(tokens)
247 tokens.setMinimumSize(new Dimension(0, 200)); 248 );
248 JSplitPane callPanel = new JSplitPane( 249 callPanel.setResizeWeight(1); // let the top side take all the slack
249 JSplitPane.VERTICAL_SPLIT, 250 callPanel.resetToPreferredSizes();
250 true, 251
251 new JScrollPane(callsTree), 252 // layout controls
252 new JScrollPane(tokens) 253 JPanel centerPanel = new JPanel();
253 ); 254 centerPanel.setLayout(new BorderLayout());
254 callPanel.setResizeWeight(1); // let the top side take all the slack 255 centerPanel.add(infoPanel, BorderLayout.NORTH);
255 callPanel.resetToPreferredSizes(); 256 centerPanel.add(sourceScroller, BorderLayout.CENTER);
256 257 tabs = new JTabbedPane();
257 // layout controls 258 tabs.setPreferredSize(new Dimension(250, 0));
258 JPanel centerPanel = new JPanel(); 259 tabs.addTab("Inheritance", inheritancePanel);
259 centerPanel.setLayout(new BorderLayout()); 260 tabs.addTab("Implementations", implementationsPanel);
260 centerPanel.add(infoPanel, BorderLayout.NORTH); 261 tabs.addTab("Call Graph", callPanel);
261 centerPanel.add(sourceScroller, BorderLayout.CENTER); 262 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabs);
262 tabs = new JTabbedPane(); 263 splitRight.setResizeWeight(1); // let the left side take all the slack
263 tabs.setPreferredSize(new Dimension(250, 0)); 264 splitRight.resetToPreferredSizes();
264 tabs.addTab("Inheritance", inheritancePanel); 265 JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, this.classesPanel, splitRight);
265 tabs.addTab("Implementations", implementationsPanel); 266 splitCenter.setResizeWeight(0); // let the right side take all the slack
266 tabs.addTab("Call Graph", callPanel); 267 pane.add(splitCenter, BorderLayout.CENTER);
267 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabs); 268
268 splitRight.setResizeWeight(1); // let the left side take all the slack 269 // init menus
269 splitRight.resetToPreferredSizes(); 270 this.menuBar = new MenuBar(this);
270 JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, this.classesPanel, splitRight); 271 this.frame.setJMenuBar(this.menuBar);
271 splitCenter.setResizeWeight(0); // let the right side take all the slack 272
272 pane.add(splitCenter, BorderLayout.CENTER); 273 // init state
273 274 onCloseJar();
274 // init menus 275
275 this.menuBar = new MenuBar(this); 276 this.frame.addWindowListener(new WindowAdapter() {
276 this.frame.setJMenuBar(this.menuBar); 277 @Override
277 278 public void windowClosing(WindowEvent event) {
278 // init state 279 close();
279 onCloseJar(); 280 }
280 281 });
281 this.frame.addWindowListener(new WindowAdapter() { 282
282 @Override 283 // show the frame
283 public void windowClosing(WindowEvent event) { 284 pane.doLayout();
284 close(); 285 this.frame.setSize(1024, 576);
285 } 286 this.frame.setMinimumSize(new Dimension(640, 480));
286 }); 287 this.frame.setVisible(true);
287 288 this.frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
288 // show the frame 289 }
289 pane.doLayout(); 290
290 this.frame.setSize(1024, 576); 291 public JFrame getFrame() {
291 this.frame.setMinimumSize(new Dimension(640, 480)); 292 return this.frame;
292 this.frame.setVisible(true); 293 }
293 this.frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 294
294 } 295 public GuiController getController() {
295 296 return this.controller;
296 public JFrame getFrame() { 297 }
297 return this.frame; 298
298 } 299 public void onStartOpenJar() {
299 300 this.classesPanel.removeAll();
300 public GuiController getController() { 301 JPanel panel = new JPanel();
301 return this.controller; 302 panel.setLayout(new FlowLayout());
302 } 303 panel.add(new JLabel("Loading..."));
303 304 this.classesPanel.add(panel);
304 public void onStartOpenJar() { 305 redraw();
305 this.classesPanel.removeAll(); 306 }
306 JPanel panel = new JPanel(); 307
307 panel.setLayout(new FlowLayout()); 308 public void onFinishOpenJar(String jarName) {
308 panel.add(new JLabel("Loading...")); 309 // update gui
309 this.classesPanel.add(panel); 310 this.frame.setTitle(Constants.NAME + " - " + jarName);
310 redraw(); 311 this.classesPanel.removeAll();
311 } 312 this.classesPanel.add(splitClasses);
312 313 setSource(null);
313 public void onFinishOpenJar(String jarName) { 314
314 // update gui 315 // update menu
315 this.frame.setTitle(Constants.NAME + " - " + jarName); 316 this.menuBar.closeJarMenu.setEnabled(true);
316 this.classesPanel.removeAll(); 317 this.menuBar.openEnigmaMappingsMenu.setEnabled(true);
317 this.classesPanel.add(splitClasses); 318 this.menuBar.saveMappingsMenu.setEnabled(false);
318 setSource(null); 319 this.menuBar.saveMappingEnigmaFileMenu.setEnabled(true);
319 320 this.menuBar.saveMappingEnigmaDirectoryMenu.setEnabled(true);
320 // update menu 321 this.menuBar.saveMappingsSrgMenu.setEnabled(true);
321 this.menuBar.closeJarMenu.setEnabled(true); 322 this.menuBar.closeMappingsMenu.setEnabled(true);
322 this.menuBar.openEnigmaMappingsMenu.setEnabled(true); 323 this.menuBar.exportSourceMenu.setEnabled(true);
323 this.menuBar.saveMappingsMenu.setEnabled(false); 324 this.menuBar.exportJarMenu.setEnabled(true);
324 this.menuBar.saveMappingEnigmaFileMenu.setEnabled(true); 325
325 this.menuBar.saveMappingEnigmaDirectoryMenu.setEnabled(true); 326 redraw();
326 this.menuBar.saveMappingsSrgMenu.setEnabled(true); 327 }
327 this.menuBar.closeMappingsMenu.setEnabled(true); 328
328 this.menuBar.exportSourceMenu.setEnabled(true); 329 public void onCloseJar() {
329 this.menuBar.exportJarMenu.setEnabled(true); 330 // update gui
330 331 this.frame.setTitle(Constants.NAME);
331 redraw(); 332 setObfClasses(null);
332 } 333 setDeobfClasses(null);
333 334 setSource(null);
334 public void onCloseJar() { 335 this.classesPanel.removeAll();
335 // update gui 336
336 this.frame.setTitle(Constants.NAME); 337 // update menu
337 setObfClasses(null); 338 this.menuBar.closeJarMenu.setEnabled(false);
338 setDeobfClasses(null); 339 this.menuBar.openEnigmaMappingsMenu.setEnabled(false);
339 setSource(null); 340 this.menuBar.saveMappingsMenu.setEnabled(false);
340 this.classesPanel.removeAll(); 341 this.menuBar.saveMappingEnigmaFileMenu.setEnabled(false);
341 342 this.menuBar.saveMappingEnigmaDirectoryMenu.setEnabled(false);
342 // update menu 343 this.menuBar.saveMappingsSrgMenu.setEnabled(false);
343 this.menuBar.closeJarMenu.setEnabled(false); 344 this.menuBar.closeMappingsMenu.setEnabled(false);
344 this.menuBar.openEnigmaMappingsMenu.setEnabled(false); 345 this.menuBar.exportSourceMenu.setEnabled(false);
345 this.menuBar.saveMappingsMenu.setEnabled(false); 346 this.menuBar.exportJarMenu.setEnabled(false);
346 this.menuBar.saveMappingEnigmaFileMenu.setEnabled(false); 347
347 this.menuBar.saveMappingEnigmaDirectoryMenu.setEnabled(false); 348 redraw();
348 this.menuBar.saveMappingsSrgMenu.setEnabled(false); 349 }
349 this.menuBar.closeMappingsMenu.setEnabled(false); 350
350 this.menuBar.exportSourceMenu.setEnabled(false); 351 public void setObfClasses(Collection<ClassEntry> obfClasses) {
351 this.menuBar.exportJarMenu.setEnabled(false); 352 this.obfPanel.obfClasses.setClasses(obfClasses);
352 353 }
353 redraw(); 354
354 } 355 public void setDeobfClasses(Collection<ClassEntry> deobfClasses) {
355 356 this.deobfPanel.deobfClasses.setClasses(deobfClasses);
356 public void setObfClasses(Collection<ClassEntry> obfClasses) { 357 }
357 this.obfPanel.obfClasses.setClasses(obfClasses); 358
358 } 359 public void setMappingsFile(File file) {
359 360 this.enigmaMappingsFileChooser.setSelectedFile(file);
360 public void setDeobfClasses(Collection<ClassEntry> deobfClasses) { 361 this.menuBar.saveMappingsMenu.setEnabled(file != null);
361 this.deobfPanel.deobfClasses.setClasses(deobfClasses); 362 }
362 } 363
363 364 public void setSource(String source) {
364 public void setMappingsFile(File file) { 365 this.editor.getHighlighter().removeAllHighlights();
365 this.enigmaMappingsFileChooser.setSelectedFile(file); 366 this.editor.setText(source);
366 this.menuBar.saveMappingsMenu.setEnabled(file != null); 367 }
367 } 368
368 369 public void showToken(final Token token) {
369 public void setSource(String source) { 370 if (token == null) {
370 this.editor.getHighlighter().removeAllHighlights(); 371 throw new IllegalArgumentException("Token cannot be null!");
371 this.editor.setText(source); 372 }
372 } 373 CodeReader.navigateToToken(this.editor, token, selectionHighlightPainter);
373 374 redraw();
374 public void showToken(final Token token) { 375 }
375 if (token == null) { 376
376 throw new IllegalArgumentException("Token cannot be null!"); 377 public void showTokens(Collection<Token> tokens) {
377 } 378 Vector<Token> sortedTokens = new Vector<>(tokens);
378 CodeReader.navigateToToken(this.editor, token, selectionHighlightPainter); 379 Collections.sort(sortedTokens);
379 redraw(); 380 if (sortedTokens.size() > 1) {
380 } 381 // sort the tokens and update the tokens panel
381 382 this.tokens.setListData(sortedTokens);
382 public void showTokens(Collection<Token> tokens) { 383 this.tokens.setSelectedIndex(0);
383 Vector<Token> sortedTokens = new Vector<>(tokens); 384 } else {
384 Collections.sort(sortedTokens); 385 this.tokens.setListData(new Vector<>());
385 if (sortedTokens.size() > 1) { 386 }
386 // sort the tokens and update the tokens panel 387
387 this.tokens.setListData(sortedTokens); 388 // show the first token
388 this.tokens.setSelectedIndex(0); 389 showToken(sortedTokens.get(0));
389 } else { 390 }
390 this.tokens.setListData(new Vector<>()); 391
391 } 392 public void setHighlightedTokens(Iterable<Token> obfuscatedTokens, Iterable<Token> deobfuscatedTokens, Iterable<Token> otherTokens) {
392 393
393 // show the first token 394 // remove any old highlighters
394 showToken(sortedTokens.get(0)); 395 this.editor.getHighlighter().removeAllHighlights();
395 } 396
396 397 // color things based on the index
397 public void setHighlightedTokens(Iterable<Token> obfuscatedTokens, Iterable<Token> deobfuscatedTokens, Iterable<Token> otherTokens) { 398 if (obfuscatedTokens != null) {
398 399 setHighlightedTokens(obfuscatedTokens, obfuscatedHighlightPainter);
399 // remove any old highlighters 400 }
400 this.editor.getHighlighter().removeAllHighlights(); 401 if (deobfuscatedTokens != null) {
401 402 setHighlightedTokens(deobfuscatedTokens, deobfuscatedHighlightPainter);
402 // color things based on the index 403 }
403 if (obfuscatedTokens != null) { 404 if (otherTokens != null) {
404 setHighlightedTokens(obfuscatedTokens, obfuscatedHighlightPainter); 405 setHighlightedTokens(otherTokens, otherHighlightPainter);
405 } 406 }
406 if (deobfuscatedTokens != null) { 407
407 setHighlightedTokens(deobfuscatedTokens, deobfuscatedHighlightPainter); 408 redraw();
408 } 409 }
409 if (otherTokens != null) { 410
410 setHighlightedTokens(otherTokens, otherHighlightPainter); 411 private void setHighlightedTokens(Iterable<Token> tokens, Highlighter.HighlightPainter painter) {
411 } 412 for (Token token : tokens) {
412 413 try {
413 redraw(); 414 this.editor.getHighlighter().addHighlight(token.start, token.end, painter);
414 } 415 } catch (BadLocationException ex) {
415 416 throw new IllegalArgumentException(ex);
416 private void setHighlightedTokens(Iterable<Token> tokens, Highlighter.HighlightPainter painter) { 417 }
417 for (Token token : tokens) { 418 }
418 try { 419 }
419 this.editor.getHighlighter().addHighlight(token.start, token.end, painter); 420
420 } catch (BadLocationException ex) { 421 private void showReference(EntryReference<Entry, Entry> reference) {
421 throw new IllegalArgumentException(ex); 422 if (reference == null) {
422 } 423 infoPanel.clearReference();
423 } 424 return;
424 } 425 }
425 426
426 private void showReference(EntryReference<Entry, Entry> reference) { 427 this.reference = reference;
427 if (reference == null) { 428
428 infoPanel.clearReference(); 429 infoPanel.removeAll();
429 return; 430 if (reference.entry instanceof ClassEntry) {
430 } 431 showClassEntry((ClassEntry) this.reference.entry);
431 432 } else if (this.reference.entry instanceof FieldEntry) {
432 this.reference = reference; 433 showFieldEntry((FieldEntry) this.reference.entry);
433 434 } else if (this.reference.entry instanceof MethodEntry) {
434 infoPanel.removeAll(); 435 showMethodEntry((MethodEntry) this.reference.entry);
435 if (reference.entry instanceof ClassEntry) { 436 } else if (this.reference.entry instanceof ConstructorEntry) {
436 showClassEntry((ClassEntry) this.reference.entry); 437 showConstructorEntry((ConstructorEntry) this.reference.entry);
437 } else if (this.reference.entry instanceof FieldEntry) { 438 } else if (this.reference.entry instanceof ArgumentEntry) {
438 showFieldEntry((FieldEntry) this.reference.entry); 439 showArgumentEntry((ArgumentEntry) this.reference.entry);
439 } else if (this.reference.entry instanceof MethodEntry) { 440 } else if (this.reference.entry instanceof LocalVariableEntry) {
440 showMethodEntry((MethodEntry) this.reference.entry); 441 showLocalVariableEntry((LocalVariableEntry) this.reference.entry);
441 } else if (this.reference.entry instanceof ConstructorEntry) { 442 } else {
442 showConstructorEntry((ConstructorEntry) this.reference.entry); 443 throw new Error("Unknown entry type: " + this.reference.entry.getClass().getName());
443 } else if (this.reference.entry instanceof ArgumentEntry) { 444 }
444 showArgumentEntry((ArgumentEntry) this.reference.entry); 445
445 } else if (this.reference.entry instanceof LocalVariableEntry) { 446 redraw();
446 showLocalVariableEntry((LocalVariableEntry) this.reference.entry); 447 }
447 } else { 448
448 throw new Error("Unknown entry type: " + this.reference.entry.getClass().getName()); 449 private void showLocalVariableEntry(LocalVariableEntry entry) {
449 } 450 addNameValue(infoPanel, "Variable", entry.getName());
450 451 addNameValue(infoPanel, "Class", entry.getClassEntry().getName());
451 redraw(); 452 addNameValue(infoPanel, "Method", entry.getBehaviorEntry().getName());
452 } 453 addNameValue(infoPanel, "Index", Integer.toString(entry.getIndex()));
453 454 addNameValue(infoPanel, "Type", entry.getType().toString());
454 private void showLocalVariableEntry(LocalVariableEntry entry) { 455 }
455 addNameValue(infoPanel, "Variable", entry.getName()); 456
456 addNameValue(infoPanel, "Class", entry.getClassEntry().getName()); 457 private void showClassEntry(ClassEntry entry) {
457 addNameValue(infoPanel, "Method", entry.getBehaviorEntry().getName()); 458 addNameValue(infoPanel, "Class", entry.getName());
458 addNameValue(infoPanel, "Index", Integer.toString(entry.getIndex())); 459 addModifierComboBox(infoPanel, "Modifier", entry);
459 addNameValue(infoPanel, "Type", entry.getType().toString()); 460 }
460 } 461
461 462 private void showFieldEntry(FieldEntry entry) {
462 private void showClassEntry(ClassEntry entry) { 463 addNameValue(infoPanel, "Field", entry.getName());
463 addNameValue(infoPanel, "Class", entry.getName()); 464 addNameValue(infoPanel, "Class", entry.getClassEntry().getName());
464 addModifierComboBox(infoPanel, "Modifier", entry); 465 addNameValue(infoPanel, "Type", entry.getType().toString());
465 } 466 addModifierComboBox(infoPanel, "Modifier", entry);
466 467 }
467 private void showFieldEntry(FieldEntry entry) { 468
468 addNameValue(infoPanel, "Field", entry.getName()); 469 private void showMethodEntry(MethodEntry entry) {
469 addNameValue(infoPanel, "Class", entry.getClassEntry().getName()); 470 addNameValue(infoPanel, "Method", entry.getName());
470 addNameValue(infoPanel, "Type", entry.getType().toString()); 471 addNameValue(infoPanel, "Class", entry.getClassEntry().getName());
471 addModifierComboBox(infoPanel, "Modifier", entry); 472 addNameValue(infoPanel, "Signature", entry.getSignature().toString());
472 } 473 addModifierComboBox(infoPanel, "Modifier", entry);
473 474
474 private void showMethodEntry(MethodEntry entry) { 475 }
475 addNameValue(infoPanel, "Method", entry.getName()); 476
476 addNameValue(infoPanel, "Class", entry.getClassEntry().getName()); 477 private void showConstructorEntry(ConstructorEntry entry) {
477 addNameValue(infoPanel, "Signature", entry.getSignature().toString()); 478 addNameValue(infoPanel, "Constructor", entry.getClassEntry().getName());
478 addModifierComboBox(infoPanel, "Modifier", entry); 479 if (!entry.isStatic()) {
479 480 addNameValue(infoPanel, "Signature", entry.getSignature().toString());
480 } 481 addModifierComboBox(infoPanel, "Modifier", entry);
481 482 }
482 private void showConstructorEntry(ConstructorEntry entry) { 483 }
483 addNameValue(infoPanel, "Constructor", entry.getClassEntry().getName()); 484
484 if (!entry.isStatic()) { 485 private void showArgumentEntry(ArgumentEntry entry) {
485 addNameValue(infoPanel, "Signature", entry.getSignature().toString()); 486 addNameValue(infoPanel, "Argument", entry.getName());
486 addModifierComboBox(infoPanel, "Modifier", entry); 487 addNameValue(infoPanel, "Class", entry.getClassEntry().getName());
487 } 488 addNameValue(infoPanel, "Method", entry.getBehaviorEntry().getName());
488 } 489 addNameValue(infoPanel, "Index", Integer.toString(entry.getIndex()));
489 490 }
490 private void showArgumentEntry(ArgumentEntry entry) { 491
491 addNameValue(infoPanel, "Argument", entry.getName()); 492 private void addNameValue(JPanel container, String name, String value) {
492 addNameValue(infoPanel, "Class", entry.getClassEntry().getName()); 493 JPanel panel = new JPanel();
493 addNameValue(infoPanel, "Method", entry.getBehaviorEntry().getName()); 494 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0));
494 addNameValue(infoPanel, "Index", Integer.toString(entry.getIndex())); 495 container.add(panel);
495 } 496
496 497 JLabel label = new JLabel(name + ":", JLabel.RIGHT);
497 private void addNameValue(JPanel container, String name, String value) { 498 label.setPreferredSize(new Dimension(100, label.getPreferredSize().height));
498 JPanel panel = new JPanel(); 499 panel.add(label);
499 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0)); 500
500 container.add(panel); 501 panel.add(Utils.unboldLabel(new JLabel(value, JLabel.LEFT)));
501 502 }
502 JLabel label = new JLabel(name + ":", JLabel.RIGHT); 503
503 label.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); 504 private JComboBox<Mappings.EntryModifier> addModifierComboBox(JPanel container, String name, Entry entry) {
504 panel.add(label); 505 if (!getController().entryIsInJar(entry))
505 506 return null;
506 panel.add(Utils.unboldLabel(new JLabel(value, JLabel.LEFT))); 507 JPanel panel = new JPanel();
507 } 508 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0));
508 509 container.add(panel);
509 private JComboBox<Mappings.EntryModifier> addModifierComboBox(JPanel container, String name, Entry entry) 510 JLabel label = new JLabel(name + ":", JLabel.RIGHT);
510 { 511 label.setPreferredSize(new Dimension(100, label.getPreferredSize().height));
511 if (!getController().entryIsInJar(entry)) 512 panel.add(label);
512 return null; 513 JComboBox<Mappings.EntryModifier> combo = new JComboBox<>(Mappings.EntryModifier.values());
513 JPanel panel = new JPanel(); 514 ((JLabel) combo.getRenderer()).setHorizontalAlignment(JLabel.LEFT);
514 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0)); 515 combo.setPreferredSize(new Dimension(100, label.getPreferredSize().height));
515 container.add(panel); 516 combo.setSelectedIndex(getController().getDeobfuscator().getModifier(entry).ordinal());
516 JLabel label = new JLabel(name + ":", JLabel.RIGHT); 517 combo.addItemListener(getController()::modifierChange);
517 label.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); 518 panel.add(combo);
518 panel.add(label); 519 return combo;
519 JComboBox<Mappings.EntryModifier> combo = new JComboBox<>(Mappings.EntryModifier.values()); 520 }
520 ((JLabel)combo.getRenderer()).setHorizontalAlignment(JLabel.LEFT); 521
521 combo.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); 522 public void onCaretMove(int pos) {
522 combo.setSelectedIndex(getController().getDeobfuscator().getModifier(entry).ordinal()); 523
523 combo.addItemListener(getController()::modifierChange); 524 Token token = this.controller.getToken(pos);
524 panel.add(combo); 525 boolean isToken = token != null;
525 return combo; 526
526 } 527 reference = this.controller.getDeobfReference(token);
527 528 boolean isClassEntry = isToken && reference.entry instanceof ClassEntry;
528 public void onCaretMove(int pos) { 529 boolean isFieldEntry = isToken && reference.entry instanceof FieldEntry;
529 530 boolean isMethodEntry = isToken && reference.entry instanceof MethodEntry;
530 Token token = this.controller.getToken(pos); 531 boolean isConstructorEntry = isToken && reference.entry instanceof ConstructorEntry;
531 boolean isToken = token != null; 532 boolean isInJar = isToken && this.controller.entryIsInJar(reference.entry);
532 533 boolean isRenameable = isToken && this.controller.referenceIsRenameable(reference);
533 reference = this.controller.getDeobfReference(token); 534
534 boolean isClassEntry = isToken && reference.entry instanceof ClassEntry; 535 if (isToken) {
535 boolean isFieldEntry = isToken && reference.entry instanceof FieldEntry; 536 showReference(reference);
536 boolean isMethodEntry = isToken && reference.entry instanceof MethodEntry; 537 } else {
537 boolean isConstructorEntry = isToken && reference.entry instanceof ConstructorEntry; 538 infoPanel.clearReference();
538 boolean isInJar = isToken && this.controller.entryIsInJar(reference.entry); 539 }
539 boolean isRenameable = isToken && this.controller.referenceIsRenameable(reference); 540
540 541 this.popupMenu.renameMenu.setEnabled(isRenameable);
541 if (isToken) { 542 this.popupMenu.showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry);
542 showReference(reference); 543 this.popupMenu.showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry);
543 } else { 544 this.popupMenu.showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry);
544 infoPanel.clearReference(); 545 this.popupMenu.openEntryMenu.setEnabled(isInJar && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry));
545 } 546 this.popupMenu.openPreviousMenu.setEnabled(this.controller.hasPreviousLocation());
546 547 this.popupMenu.toggleMappingMenu.setEnabled(isRenameable);
547 this.popupMenu.renameMenu.setEnabled(isRenameable); 548
548 this.popupMenu.showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry); 549 if (isToken && this.controller.entryHasDeobfuscatedName(reference.entry)) {
549 this.popupMenu.showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry); 550 this.popupMenu.toggleMappingMenu.setText("Reset to obfuscated");
550 this.popupMenu.showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry); 551 } else {
551 this.popupMenu.openEntryMenu.setEnabled(isInJar && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry)); 552 this.popupMenu.toggleMappingMenu.setText("Mark as deobfuscated");
552 this.popupMenu.openPreviousMenu.setEnabled(this.controller.hasPreviousLocation()); 553 }
553 this.popupMenu.toggleMappingMenu.setEnabled(isRenameable); 554 }
554 555
555 if (isToken && this.controller.entryHasDeobfuscatedName(reference.entry)) { 556 public void navigateTo(Entry entry) {
556 this.popupMenu.toggleMappingMenu.setText("Reset to obfuscated"); 557 if (!this.controller.entryIsInJar(entry)) {
557 } else { 558 // entry is not in the jar. Ignore it
558 this.popupMenu.toggleMappingMenu.setText("Mark as deobfuscated"); 559 return;
559 } 560 }
560 } 561 if (reference != null) {
561 562 this.controller.savePreviousReference(reference);
562 public void navigateTo(Entry entry) { 563 }
563 if (!this.controller.entryIsInJar(entry)) { 564 this.controller.openDeclaration(entry);
564 // entry is not in the jar. Ignore it 565 }
565 return; 566
566 } 567 private void navigateTo(EntryReference<Entry, Entry> reference) {
567 if (reference != null) { 568 if (!this.controller.entryIsInJar(reference.getLocationClassEntry())) {
568 this.controller.savePreviousReference(reference); 569 return;
569 } 570 }
570 this.controller.openDeclaration(entry); 571 if (this.reference != null) {
571 } 572 this.controller.savePreviousReference(this.reference);
572 573 }
573 private void navigateTo(EntryReference<Entry, Entry> reference) { 574 this.controller.openReference(reference);
574 if (!this.controller.entryIsInJar(reference.getLocationClassEntry())) { 575 }
575 return; 576
576 } 577 public void startRename() {
577 if (this.reference != null) { 578
578 this.controller.savePreviousReference(this.reference); 579 // init the text box
579 } 580 final JTextField text = new JTextField();
580 this.controller.openReference(reference); 581 text.setText(reference.getNamableName());
581 } 582 text.setPreferredSize(new Dimension(360, text.getPreferredSize().height));
582 583 text.addKeyListener(new KeyAdapter() {
583 public void startRename() { 584 @Override
584 585 public void keyPressed(KeyEvent event) {
585 // init the text box 586 switch (event.getKeyCode()) {
586 final JTextField text = new JTextField(); 587 case KeyEvent.VK_ENTER:
587 text.setText(reference.getNamableName()); 588 finishRename(text, true);
588 text.setPreferredSize(new Dimension(360, text.getPreferredSize().height)); 589 break;
589 text.addKeyListener(new KeyAdapter() { 590
590 @Override 591 case KeyEvent.VK_ESCAPE:
591 public void keyPressed(KeyEvent event) { 592 finishRename(text, false);
592 switch (event.getKeyCode()) { 593 break;
593 case KeyEvent.VK_ENTER: 594 default:
594 finishRename(text, true); 595 break;
595 break; 596 }
596 597 }
597 case KeyEvent.VK_ESCAPE: 598 });
598 finishRename(text, false); 599
599 break; 600 // find the label with the name and replace it with the text box
600 default: 601 JPanel panel = (JPanel) infoPanel.getComponent(0);
601 break; 602 panel.remove(panel.getComponentCount() - 1);
602 } 603 panel.add(text);
603 } 604 text.grabFocus();
604 }); 605
605 606 int offset = text.getText().lastIndexOf('/') + 1;
606 // find the label with the name and replace it with the text box 607 // If it's a class and isn't in the default package, assume that it's deobfuscated.
607 JPanel panel = (JPanel) infoPanel.getComponent(0); 608 if (reference.getNameableEntry() instanceof ClassEntry && text.getText().contains("/") && offset != 0)
608 panel.remove(panel.getComponentCount() - 1); 609 text.select(offset, text.getText().length());
609 panel.add(text); 610 else
610 text.grabFocus(); 611 text.selectAll();
611 612
612 int offset = text.getText().lastIndexOf('/') + 1; 613 redraw();
613 // If it's a class and isn't in the default package, assume that it's deobfuscated. 614 }
614 if (reference.getNameableEntry() instanceof ClassEntry && text.getText().contains("/") && offset != 0) 615
615 text.select(offset, text.getText().length()); 616 private void finishRename(JTextField text, boolean saveName) {
616 else 617 String newName = text.getText();
617 text.selectAll(); 618 if (saveName && newName != null && !newName.isEmpty()) {
618 619 try {
619 redraw(); 620 this.controller.rename(reference, newName);
620 } 621 } catch (IllegalNameException ex) {
621 622 text.setBorder(BorderFactory.createLineBorder(Color.red, 1));
622 private void finishRename(JTextField text, boolean saveName) { 623 text.setToolTipText(ex.getReason());
623 String newName = text.getText(); 624 Utils.showToolTipNow(text);
624 if (saveName && newName != null && newName.length() > 0) { 625 }
625 try { 626 return;
626 this.controller.rename(reference, newName); 627 }
627 } catch (IllegalNameException ex) { 628
628 text.setBorder(BorderFactory.createLineBorder(Color.red, 1)); 629 // abort the rename
629 text.setToolTipText(ex.getReason()); 630 JPanel panel = (JPanel) infoPanel.getComponent(0);
630 Utils.showToolTipNow(text); 631 panel.remove(panel.getComponentCount() - 1);
631 } 632 panel.add(Utils.unboldLabel(new JLabel(reference.getNamableName(), JLabel.LEFT)));
632 return; 633
633 } 634 this.editor.grabFocus();
634 635
635 // abort the rename 636 redraw();
636 JPanel panel = (JPanel) infoPanel.getComponent(0); 637 }
637 panel.remove(panel.getComponentCount() - 1); 638
638 panel.add(Utils.unboldLabel(new JLabel(reference.getNamableName(), JLabel.LEFT))); 639 public void showInheritance() {
639 640
640 this.editor.grabFocus(); 641 if (reference == null) {
641 642 return;
642 redraw(); 643 }
643 } 644
644 645 inheritanceTree.setModel(null);
645 public void showInheritance() { 646
646 647 if (reference.entry instanceof ClassEntry) {
647 if (reference == null) { 648 // get the class inheritance
648 return; 649 ClassInheritanceTreeNode classNode = this.controller.getClassInheritance((ClassEntry) reference.entry);
649 } 650
650 651 // show the tree at the root
651 inheritanceTree.setModel(null); 652 TreePath path = getPathToRoot(classNode);
652 653 inheritanceTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
653 if (reference.entry instanceof ClassEntry) { 654 inheritanceTree.expandPath(path);
654 // get the class inheritance 655 inheritanceTree.setSelectionRow(inheritanceTree.getRowForPath(path));
655 ClassInheritanceTreeNode classNode = this.controller.getClassInheritance((ClassEntry) reference.entry); 656 } else if (reference.entry instanceof MethodEntry) {
656 657 // get the method inheritance
657 // show the tree at the root 658 MethodInheritanceTreeNode classNode = this.controller.getMethodInheritance((MethodEntry) reference.entry);
658 TreePath path = getPathToRoot(classNode); 659
659 inheritanceTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0))); 660 // show the tree at the root
660 inheritanceTree.expandPath(path); 661 TreePath path = getPathToRoot(classNode);
661 inheritanceTree.setSelectionRow(inheritanceTree.getRowForPath(path)); 662 inheritanceTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
662 } else if (reference.entry instanceof MethodEntry) { 663 inheritanceTree.expandPath(path);
663 // get the method inheritance 664 inheritanceTree.setSelectionRow(inheritanceTree.getRowForPath(path));
664 MethodInheritanceTreeNode classNode = this.controller.getMethodInheritance((MethodEntry) reference.entry); 665 }
665 666
666 // show the tree at the root 667 tabs.setSelectedIndex(0);
667 TreePath path = getPathToRoot(classNode); 668 redraw();
668 inheritanceTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0))); 669 }
669 inheritanceTree.expandPath(path); 670
670 inheritanceTree.setSelectionRow(inheritanceTree.getRowForPath(path)); 671 public void showImplementations() {
671 } 672
672 673 if (reference == null) {
673 tabs.setSelectedIndex(0); 674 return;
674 redraw(); 675 }
675 } 676
676 677 implementationsTree.setModel(null);
677 public void showImplementations() { 678
678 679 DefaultMutableTreeNode node = null;
679 if (reference == null) { 680
680 return; 681 // get the class implementations
681 } 682 if (reference.entry instanceof ClassEntry)
682 683 node = this.controller.getClassImplementations((ClassEntry) reference.entry);
683 implementationsTree.setModel(null); 684 else // get the method implementations
684 685 if (reference.entry instanceof MethodEntry)
685 DefaultMutableTreeNode node = null; 686 node = this.controller.getMethodImplementations((MethodEntry) reference.entry);
686 687
687 // get the class implementations 688 if (node != null) {
688 if (reference.entry instanceof ClassEntry) 689 // show the tree at the root
689 node = this.controller.getClassImplementations((ClassEntry) reference.entry); 690 TreePath path = getPathToRoot(node);
690 else // get the method implementations 691 implementationsTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
691 if (reference.entry instanceof MethodEntry) 692 implementationsTree.expandPath(path);
692 node = this.controller.getMethodImplementations((MethodEntry) reference.entry); 693 implementationsTree.setSelectionRow(implementationsTree.getRowForPath(path));
693 694 }
694 if (node != null) { 695
695 // show the tree at the root 696 tabs.setSelectedIndex(1);
696 TreePath path = getPathToRoot(node); 697 redraw();
697 implementationsTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0))); 698 }
698 implementationsTree.expandPath(path); 699
699 implementationsTree.setSelectionRow(implementationsTree.getRowForPath(path)); 700 public void showCalls() {
700 } 701 if (reference == null) {
701 702 return;
702 tabs.setSelectedIndex(1); 703 }
703 redraw(); 704
704 } 705 if (reference.entry instanceof ClassEntry) {
705 706 // look for calls to the default constructor
706 public void showCalls() { 707 // TODO: get a list of all the constructors and find calls to all of them
707 if (reference == null) { 708 BehaviorReferenceTreeNode node = this.controller.getMethodReferences(new ConstructorEntry((ClassEntry) reference.entry, new Signature("()V")));
708 return; 709 callsTree.setModel(new DefaultTreeModel(node));
709 } 710 } else if (reference.entry instanceof FieldEntry) {
710 711 FieldReferenceTreeNode node = this.controller.getFieldReferences((FieldEntry) reference.entry);
711 if (reference.entry instanceof ClassEntry) { 712 callsTree.setModel(new DefaultTreeModel(node));
712 // look for calls to the default constructor 713 } else if (reference.entry instanceof MethodEntry) {
713 // TODO: get a list of all the constructors and find calls to all of them 714 BehaviorReferenceTreeNode node = this.controller.getMethodReferences((MethodEntry) reference.entry);
714 BehaviorReferenceTreeNode node = this.controller.getMethodReferences(new ConstructorEntry((ClassEntry) reference.entry, new Signature("()V"))); 715 callsTree.setModel(new DefaultTreeModel(node));
715 callsTree.setModel(new DefaultTreeModel(node)); 716 } else if (reference.entry instanceof ConstructorEntry) {
716 } else if (reference.entry instanceof FieldEntry) { 717 BehaviorReferenceTreeNode node = this.controller.getMethodReferences((ConstructorEntry) reference.entry);
717 FieldReferenceTreeNode node = this.controller.getFieldReferences((FieldEntry) reference.entry); 718 callsTree.setModel(new DefaultTreeModel(node));
718 callsTree.setModel(new DefaultTreeModel(node)); 719 }
719 } else if (reference.entry instanceof MethodEntry) { 720
720 BehaviorReferenceTreeNode node = this.controller.getMethodReferences((MethodEntry) reference.entry); 721 tabs.setSelectedIndex(2);
721 callsTree.setModel(new DefaultTreeModel(node)); 722 redraw();
722 } else if (reference.entry instanceof ConstructorEntry) { 723 }
723 BehaviorReferenceTreeNode node = this.controller.getMethodReferences((ConstructorEntry) reference.entry); 724
724 callsTree.setModel(new DefaultTreeModel(node)); 725 public void toggleMapping() {
725 } 726 if (this.controller.entryHasDeobfuscatedName(reference.entry)) {
726 727 this.controller.removeMapping(reference);
727 tabs.setSelectedIndex(2); 728 } else {
728 redraw(); 729 this.controller.markAsDeobfuscated(reference);
729 } 730 }
730 731 }
731 public void toggleMapping() { 732
732 if (this.controller.entryHasDeobfuscatedName(reference.entry)) { 733 private TreePath getPathToRoot(TreeNode node) {
733 this.controller.removeMapping(reference); 734 List<TreeNode> nodes = Lists.newArrayList();
734 } else { 735 TreeNode n = node;
735 this.controller.markAsDeobfuscated(reference); 736 do {
736 } 737 nodes.add(n);
737 } 738 n = n.getParent();
738 739 } while (n != null);
739 private TreePath getPathToRoot(TreeNode node) { 740 Collections.reverse(nodes);
740 List<TreeNode> nodes = Lists.newArrayList(); 741 return new TreePath(nodes.toArray());
741 TreeNode n = node; 742 }
742 do { 743
743 nodes.add(n); 744 public void showDiscardDiag(Function<Integer, Void> callback, String... options) {
744 n = n.getParent(); 745 int response = JOptionPane.showOptionDialog(this.frame, "Your mappings have not been saved yet. Do you want to save?", "Save your changes?", JOptionPane.YES_NO_CANCEL_OPTION,
745 } while (n != null); 746 JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
746 Collections.reverse(nodes); 747 callback.apply(response);
747 return new TreePath(nodes.toArray()); 748 }
748 } 749
749 750 public void saveMapping() throws IOException {
750 public void showDiscardDiag(Function<Integer, Void> callback, String... options) 751 if (this.enigmaMappingsFileChooser.getSelectedFile() != null || this.enigmaMappingsFileChooser.showSaveDialog(this.frame) == JFileChooser.APPROVE_OPTION)
751 { 752 this.controller.saveMappings(this.enigmaMappingsFileChooser.getSelectedFile());
752 int response = JOptionPane.showOptionDialog(this.frame, "Your mappings have not been saved yet. Do you want to save?", "Save your changes?", JOptionPane.YES_NO_CANCEL_OPTION, 753 }
753 JOptionPane.QUESTION_MESSAGE, null, options, options[2]); 754
754 callback.apply(response); 755 public void close() {
755 } 756 if (!this.controller.isDirty()) {
756 757 // everything is saved, we can exit safely
757 public void saveMapping() throws IOException 758 this.frame.dispose();
758 { 759 System.exit(0);
759 if (this.enigmaMappingsFileChooser.getSelectedFile() != null || this.enigmaMappingsFileChooser.showSaveDialog(this.frame) == JFileChooser.APPROVE_OPTION) 760 } else {
760 this.controller.saveMappings(this.enigmaMappingsFileChooser.getSelectedFile()); 761 // ask to save before closing
761 } 762 showDiscardDiag((response) -> {
762 763 if (response == JOptionPane.YES_OPTION) {
763 public void close() { 764 try {
764 if (!this.controller.isDirty()) { 765 this.saveMapping();
765 // everything is saved, we can exit safely 766 this.frame.dispose();
766 this.frame.dispose(); 767
767 System.exit(0); 768 } catch (IOException ex) {
768 } else { 769 throw new Error(ex);
769 // ask to save before closing 770 }
770 showDiscardDiag((response) -> { 771 } else if (response == JOptionPane.NO_OPTION)
771 if (response == JOptionPane.YES_OPTION) 772 this.frame.dispose();
772 { 773
773 try { 774 return null;
774 this.saveMapping(); 775 }, "Save and exit", "Discard changes", "Cancel");
775 this.frame.dispose(); 776 }
776 777 }
777 } catch (IOException ex) { 778
778 throw new Error(ex); 779 public void redraw() {
779 } 780 this.frame.validate();
780 } 781 this.frame.repaint();
781 else if (response == JOptionPane.NO_OPTION) 782 }
782 this.frame.dispose(); 783
783 784 public void onPanelRename(Object prevData, Object data, DefaultMutableTreeNode node) throws IllegalNameException {
784 return null; 785 // package rename
785 }, "Save and exit", "Discard changes", "Cancel"); 786 if (data instanceof String) {
786 } 787 for (int i = 0; i < node.getChildCount(); i++) {
787 } 788 data = Descriptor.toJvmName((String) data);
788 789 DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) node.getChildAt(i);
789 public void redraw() { 790 ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject();
790 this.frame.validate(); 791 ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName());
791 this.frame.repaint(); 792 this.controller.rename(new EntryReference<>(prevDataChild, prevDataChild.getName()), dataChild.getName(), false, i + 1 == node.getChildCount());
792 } 793 childNode.setUserObject(dataChild);
793 794 }
794 public void onPanelRename(Object prevData, Object data, DefaultMutableTreeNode node) throws IllegalNameException 795 node.setUserObject(data);
795 { 796 // Ob package will never be modified, just reload deob view
796 // package rename 797 this.deobfPanel.deobfClasses.reload();
797 if (data instanceof String) 798 }
798 { 799 // class rename
799 for (int i = 0; i < node.getChildCount(); i++) 800 else if (data instanceof ClassEntry)
800 { 801 this.controller.rename(new EntryReference<>((ClassEntry) prevData, ((ClassEntry) prevData).getName()), ((ClassEntry) data).getName(), false, true);
801 data = Descriptor.toJvmName((String) data); 802 }
802 DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) node.getChildAt(i); 803
803 ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); 804 public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName) {
804 ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); 805 String oldEntry = deobfReference.entry.getClassEntry().getPackageName();
805 this.controller.rename(new EntryReference<>(prevDataChild, prevDataChild.getName()), dataChild.getName(), false, i + 1 == node.getChildCount()); 806 String newEntry = new ClassEntry(Descriptor.toJvmName(newName)).getPackageName();
806 childNode.setUserObject(dataChild); 807 moveClassTree(deobfReference, newName, oldEntry == null,
807 } 808 newEntry == null);
808 node.setUserObject(data); 809 }
809 // Ob package will never be modified, just reload deob view 810
810 this.deobfPanel.deobfClasses.reload(); 811 public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName, boolean isOldOb, boolean isNewOb) {
811 } 812 ClassEntry oldEntry = deobfReference.entry.getClassEntry();
812 // class rename 813 ClassEntry newEntry = new ClassEntry(Descriptor.toJvmName(newName));
813 else if (data instanceof ClassEntry) 814
814 this.controller.rename(new EntryReference<>((ClassEntry) prevData, ((ClassEntry) prevData).getName()), ((ClassEntry) data).getName(), false, true); 815 // Ob -> deob
815 } 816 if (isOldOb && !isNewOb) {
816 817 this.deobfPanel.deobfClasses.moveClassTree(oldEntry, newEntry, obfPanel.obfClasses);
817 public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName) 818 ClassSelectorPackageNode packageNode = this.obfPanel.obfClasses.getPackageNode(oldEntry);
818 { 819 this.obfPanel.obfClasses.removeNode(packageNode, oldEntry);
819 String oldEntry = deobfReference.entry.getClassEntry().getPackageName(); 820 this.obfPanel.obfClasses.removeNodeIfEmpty(packageNode);
820 String newEntry = new ClassEntry(Descriptor.toJvmName(newName)).getPackageName(); 821 this.deobfPanel.deobfClasses.reload();
821 moveClassTree(deobfReference, newName, oldEntry == null, 822 this.obfPanel.obfClasses.reload();
822 newEntry == null); 823 }
823 } 824 // Deob -> ob
824 825 else if (isNewOb && !isOldOb) {
825 public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName, boolean isOldOb, boolean isNewOb) 826 this.obfPanel.obfClasses.moveClassTree(oldEntry, newEntry, deobfPanel.deobfClasses);
826 { 827 ClassSelectorPackageNode packageNode = this.deobfPanel.deobfClasses.getPackageNode(oldEntry);
827 ClassEntry oldEntry = deobfReference.entry.getClassEntry(); 828 this.deobfPanel.deobfClasses.removeNode(packageNode, oldEntry);
828 ClassEntry newEntry = new ClassEntry(Descriptor.toJvmName(newName)); 829 this.deobfPanel.deobfClasses.removeNodeIfEmpty(packageNode);
829 830 this.deobfPanel.deobfClasses.reload();
830 // Ob -> deob 831 this.obfPanel.obfClasses.reload();
831 if (isOldOb && !isNewOb) 832 }
832 { 833 // Local move
833 this.deobfPanel.deobfClasses.moveClassTree(oldEntry, newEntry, obfPanel.obfClasses); 834 else if (isOldOb) {
834 ClassSelectorPackageNode packageNode = this.obfPanel.obfClasses.getPackageNode(oldEntry); 835 this.obfPanel.obfClasses.moveClassTree(oldEntry, newEntry, null);
835 this.obfPanel.obfClasses.removeNode(packageNode, oldEntry); 836 this.obfPanel.obfClasses.removeNodeIfEmpty(this.obfPanel.obfClasses.getPackageNode(oldEntry));
836 this.obfPanel.obfClasses.removeNodeIfEmpty(packageNode); 837 this.obfPanel.obfClasses.reload();
837 this.deobfPanel.deobfClasses.reload(); 838 } else {
838 this.obfPanel.obfClasses.reload(); 839 this.deobfPanel.deobfClasses.moveClassTree(oldEntry, newEntry, null);
839 } 840 this.deobfPanel.deobfClasses.removeNodeIfEmpty(this.deobfPanel.deobfClasses.getPackageNode(oldEntry));
840 // Deob -> ob 841 this.deobfPanel.deobfClasses.reload();
841 else if (isNewOb && !isOldOb) 842 }
842 { 843 }
843 this.obfPanel.obfClasses.moveClassTree(oldEntry, newEntry, deobfPanel.deobfClasses);
844 ClassSelectorPackageNode packageNode = this.deobfPanel.deobfClasses.getPackageNode(oldEntry);
845 this.deobfPanel.deobfClasses.removeNode(packageNode, oldEntry);
846 this.deobfPanel.deobfClasses.removeNodeIfEmpty(packageNode);
847 this.deobfPanel.deobfClasses.reload();
848 this.obfPanel.obfClasses.reload();
849 }
850 // Local move
851 else if (isOldOb)
852 {
853 this.obfPanel.obfClasses.moveClassTree(oldEntry, newEntry, null);
854 this.obfPanel.obfClasses.removeNodeIfEmpty(this.obfPanel.obfClasses.getPackageNode(oldEntry));
855 this.obfPanel.obfClasses.reload();
856 }
857 else
858 {
859 this.deobfPanel.deobfClasses.moveClassTree(oldEntry, newEntry, null);
860 this.deobfPanel.deobfClasses.removeNodeIfEmpty(this.deobfPanel.deobfClasses.getPackageNode(oldEntry));
861 this.deobfPanel.deobfClasses.reload();
862 }
863 }
864} 844}