summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/gui/Gui.java
diff options
context:
space:
mode:
authorGravatar lclc982016-06-30 00:49:21 +1000
committerGravatar GitHub2016-06-30 00:49:21 +1000
commit4be005617b3b8c3578cca07c5d085d12916f0d1d (patch)
treedb163431f38703e26da417ef05eaea2b27a498b9 /src/main/java/cuchaz/enigma/gui/Gui.java
parentSome small changes to fix idea importing (diff)
downloadenigma-fork-4be005617b3b8c3578cca07c5d085d12916f0d1d.tar.gz
enigma-fork-4be005617b3b8c3578cca07c5d085d12916f0d1d.tar.xz
enigma-fork-4be005617b3b8c3578cca07c5d085d12916f0d1d.zip
Json format (#2)
* Added new format * Fixed bug * Updated Version
Diffstat (limited to 'src/main/java/cuchaz/enigma/gui/Gui.java')
-rw-r--r--src/main/java/cuchaz/enigma/gui/Gui.java1100
1 files changed, 1100 insertions, 0 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java
new file mode 100644
index 0000000..eb26ddd
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -0,0 +1,1100 @@
1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html
7 * <p>
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.gui;
12
13import com.google.common.collect.Lists;
14
15import java.awt.*;
16import java.awt.event.*;
17import java.io.File;
18import java.io.IOException;
19import java.lang.Thread.UncaughtExceptionHandler;
20import java.util.Collection;
21import java.util.Collections;
22import java.util.List;
23import java.util.Vector;
24import java.util.jar.JarFile;
25
26import javax.swing.*;
27import javax.swing.event.CaretEvent;
28import javax.swing.event.CaretListener;
29import javax.swing.text.BadLocationException;
30import javax.swing.text.Highlighter;
31import javax.swing.tree.DefaultTreeModel;
32import javax.swing.tree.TreeNode;
33import javax.swing.tree.TreePath;
34
35import cuchaz.enigma.Constants;
36import cuchaz.enigma.ExceptionIgnorer;
37import cuchaz.enigma.analysis.*;
38import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
39import cuchaz.enigma.mapping.*;
40import de.sciss.syntaxpane.DefaultSyntaxKit;
41
42public class Gui {
43
44 private GuiController m_controller;
45
46 // controls
47 private JFrame m_frame;
48 private ClassSelector m_obfClasses;
49 private ClassSelector m_deobfClasses;
50 private JEditorPane m_editor;
51 private JPanel m_classesPanel;
52 private JSplitPane m_splitClasses;
53 private JPanel m_infoPanel;
54 private ObfuscatedHighlightPainter m_obfuscatedHighlightPainter;
55 private DeobfuscatedHighlightPainter m_deobfuscatedHighlightPainter;
56 private OtherHighlightPainter m_otherHighlightPainter;
57 private SelectionHighlightPainter m_selectionHighlightPainter;
58 private JTree m_inheritanceTree;
59 private JTree m_implementationsTree;
60 private JTree m_callsTree;
61 private JList<Token> m_tokens;
62 private JTabbedPane m_tabs;
63
64 // dynamic menu items
65 private JMenuItem m_closeJarMenu;
66 private JMenuItem m_openMappingsMenu;
67 private JMenuItem m_openOldMappingsMenu;
68 private JMenuItem m_saveMappingsMenu;
69 private JMenuItem m_saveMappingsAsMenu;
70 private JMenuItem m_closeMappingsMenu;
71 private JMenuItem m_renameMenu;
72 private JMenuItem m_showInheritanceMenu;
73 private JMenuItem m_openEntryMenu;
74 private JMenuItem m_openPreviousMenu;
75 private JMenuItem m_showCallsMenu;
76 private JMenuItem m_showImplementationsMenu;
77 private JMenuItem m_toggleMappingMenu;
78 private JMenuItem m_exportSourceMenu;
79 private JMenuItem m_exportJarMenu;
80
81 // state
82 private EntryReference<Entry, Entry> m_reference;
83 private JFileChooser m_jarFileChooser;
84 private JFileChooser m_mappingsFileChooser;
85 private JFileChooser m_oldMappingsFileChooser;
86
87 private JFileChooser m_exportSourceFileChooser;
88 private JFileChooser m_exportJarFileChooser;
89
90 public Gui() {
91
92 // init frame
93 m_frame = new JFrame(Constants.Name);
94 final Container pane = m_frame.getContentPane();
95 pane.setLayout(new BorderLayout());
96
97 if (Boolean.parseBoolean(System.getProperty("enigma.catchExceptions", "true"))) {
98 // install a global exception handler to the event thread
99 CrashDialog.init(m_frame);
100 Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
101 @Override
102 public void uncaughtException(Thread thread, Throwable t) {
103 t.printStackTrace(System.err);
104 if (!ExceptionIgnorer.shouldIgnore(t)) {
105 CrashDialog.show(t);
106 }
107 }
108 });
109 }
110
111 m_controller = new GuiController(this);
112
113 // init file choosers
114 m_jarFileChooser = new JFileChooser();
115 m_mappingsFileChooser = new JFileChooser();
116 m_mappingsFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
117 m_mappingsFileChooser.setAcceptAllFileFilterUsed(false);
118
119 m_oldMappingsFileChooser= new JFileChooser();
120 m_exportSourceFileChooser = new JFileChooser();
121 m_exportSourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
122 m_exportJarFileChooser = new JFileChooser();
123
124 // init obfuscated classes list
125 m_obfClasses = new ClassSelector(ClassSelector.ObfuscatedClassEntryComparator);
126 m_obfClasses.setListener(new ClassSelectionListener() {
127 @Override
128 public void onSelectClass(ClassEntry classEntry) {
129 navigateTo(classEntry);
130 }
131 });
132 JScrollPane obfScroller = new JScrollPane(m_obfClasses);
133 JPanel obfPanel = new JPanel();
134 obfPanel.setLayout(new BorderLayout());
135 obfPanel.add(new JLabel("Obfuscated Classes"), BorderLayout.NORTH);
136 obfPanel.add(obfScroller, BorderLayout.CENTER);
137
138 // init deobfuscated classes list
139 m_deobfClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator);
140 m_deobfClasses.setListener(new ClassSelectionListener() {
141 @Override
142 public void onSelectClass(ClassEntry classEntry) {
143 navigateTo(classEntry);
144 }
145 });
146 JScrollPane deobfScroller = new JScrollPane(m_deobfClasses);
147 JPanel deobfPanel = new JPanel();
148 deobfPanel.setLayout(new BorderLayout());
149 deobfPanel.add(new JLabel("De-obfuscated Classes"), BorderLayout.NORTH);
150 deobfPanel.add(deobfScroller, BorderLayout.CENTER);
151
152 // set up classes panel (don't add the splitter yet)
153 m_splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel);
154 m_splitClasses.setResizeWeight(0.3);
155 m_classesPanel = new JPanel();
156 m_classesPanel.setLayout(new BorderLayout());
157 m_classesPanel.setPreferredSize(new Dimension(250, 0));
158
159 // init info panel
160 m_infoPanel = new JPanel();
161 m_infoPanel.setLayout(new GridLayout(4, 1, 0, 0));
162 m_infoPanel.setPreferredSize(new Dimension(0, 100));
163 m_infoPanel.setBorder(BorderFactory.createTitledBorder("Identifier Info"));
164 clearReference();
165
166 // init editor
167 DefaultSyntaxKit.initKit();
168 m_obfuscatedHighlightPainter = new ObfuscatedHighlightPainter();
169 m_deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter();
170 m_otherHighlightPainter = new OtherHighlightPainter();
171 m_selectionHighlightPainter = new SelectionHighlightPainter();
172 m_editor = new JEditorPane();
173 m_editor.setEditable(false);
174 m_editor.setCaret(new BrowserCaret());
175 JScrollPane sourceScroller = new JScrollPane(m_editor);
176 m_editor.setContentType("text/java");
177 m_editor.addCaretListener(new CaretListener() {
178 @Override
179 public void caretUpdate(CaretEvent event) {
180 onCaretMove(event.getDot());
181 }
182 });
183 m_editor.addKeyListener(new KeyAdapter() {
184 @Override
185 public void keyPressed(KeyEvent event) {
186 switch (event.getKeyCode()) {
187 case KeyEvent.VK_R:
188 m_renameMenu.doClick();
189 break;
190
191 case KeyEvent.VK_I:
192 m_showInheritanceMenu.doClick();
193 break;
194
195 case KeyEvent.VK_M:
196 m_showImplementationsMenu.doClick();
197 break;
198
199 case KeyEvent.VK_N:
200 m_openEntryMenu.doClick();
201 break;
202
203 case KeyEvent.VK_P:
204 m_openPreviousMenu.doClick();
205 break;
206
207 case KeyEvent.VK_C:
208 m_showCallsMenu.doClick();
209 break;
210
211 case KeyEvent.VK_T:
212 m_toggleMappingMenu.doClick();
213 break;
214 }
215 }
216 });
217
218 // turn off token highlighting (it's wrong most of the time anyway...)
219 DefaultSyntaxKit kit = (DefaultSyntaxKit) m_editor.getEditorKit();
220 kit.toggleComponent(m_editor, "de.sciss.syntaxpane.components.TokenMarker");
221
222 // init editor popup menu
223 JPopupMenu popupMenu = new JPopupMenu();
224 m_editor.setComponentPopupMenu(popupMenu);
225 {
226 JMenuItem menu = new JMenuItem("Rename");
227 menu.addActionListener(new ActionListener() {
228 @Override
229 public void actionPerformed(ActionEvent event) {
230 startRename();
231 }
232 });
233 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0));
234 menu.setEnabled(false);
235 popupMenu.add(menu);
236 m_renameMenu = menu;
237 }
238 {
239 JMenuItem menu = new JMenuItem("Show Inheritance");
240 menu.addActionListener(new ActionListener() {
241 @Override
242 public void actionPerformed(ActionEvent event) {
243 showInheritance();
244 }
245 });
246 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, 0));
247 menu.setEnabled(false);
248 popupMenu.add(menu);
249 m_showInheritanceMenu = menu;
250 }
251 {
252 JMenuItem menu = new JMenuItem("Show Implementations");
253 menu.addActionListener(new ActionListener() {
254 @Override
255 public void actionPerformed(ActionEvent event) {
256 showImplementations();
257 }
258 });
259 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0));
260 menu.setEnabled(false);
261 popupMenu.add(menu);
262 m_showImplementationsMenu = menu;
263 }
264 {
265 JMenuItem menu = new JMenuItem("Show Calls");
266 menu.addActionListener(new ActionListener() {
267 @Override
268 public void actionPerformed(ActionEvent event) {
269 showCalls();
270 }
271 });
272 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0));
273 menu.setEnabled(false);
274 popupMenu.add(menu);
275 m_showCallsMenu = menu;
276 }
277 {
278 JMenuItem menu = new JMenuItem("Go to Declaration");
279 menu.addActionListener(new ActionListener() {
280 @Override
281 public void actionPerformed(ActionEvent event) {
282 navigateTo(m_reference.entry);
283 }
284 });
285 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0));
286 menu.setEnabled(false);
287 popupMenu.add(menu);
288 m_openEntryMenu = menu;
289 }
290 {
291 JMenuItem menu = new JMenuItem("Go to previous");
292 menu.addActionListener(new ActionListener() {
293 @Override
294 public void actionPerformed(ActionEvent event) {
295 m_controller.openPreviousReference();
296 }
297 });
298 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0));
299 menu.setEnabled(false);
300 popupMenu.add(menu);
301 m_openPreviousMenu = menu;
302 }
303 {
304 JMenuItem menu = new JMenuItem("Mark as deobfuscated");
305 menu.addActionListener(new ActionListener() {
306 @Override
307 public void actionPerformed(ActionEvent event) {
308 toggleMapping();
309 }
310 });
311 menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0));
312 menu.setEnabled(false);
313 popupMenu.add(menu);
314 m_toggleMappingMenu = menu;
315 }
316
317 // init inheritance panel
318 m_inheritanceTree = new JTree();
319 m_inheritanceTree.setModel(null);
320 m_inheritanceTree.addMouseListener(new MouseAdapter() {
321 @Override
322 public void mouseClicked(MouseEvent event) {
323 if (event.getClickCount() == 2) {
324 // get the selected node
325 TreePath path = m_inheritanceTree.getSelectionPath();
326 if (path == null) {
327 return;
328 }
329
330 Object node = path.getLastPathComponent();
331 if (node instanceof ClassInheritanceTreeNode) {
332 ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode) node;
333 navigateTo(new ClassEntry(classNode.getObfClassName()));
334 } else if (node instanceof MethodInheritanceTreeNode) {
335 MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode) node;
336 if (methodNode.isImplemented()) {
337 navigateTo(methodNode.getMethodEntry());
338 }
339 }
340 }
341 }
342 });
343 JPanel inheritancePanel = new JPanel();
344 inheritancePanel.setLayout(new BorderLayout());
345 inheritancePanel.add(new JScrollPane(m_inheritanceTree));
346
347 // init implementations panel
348 m_implementationsTree = new JTree();
349 m_implementationsTree.setModel(null);
350 m_implementationsTree.addMouseListener(new MouseAdapter() {
351 @Override
352 public void mouseClicked(MouseEvent event) {
353 if (event.getClickCount() == 2) {
354 // get the selected node
355 TreePath path = m_implementationsTree.getSelectionPath();
356 if (path == null) {
357 return;
358 }
359
360 Object node = path.getLastPathComponent();
361 if (node instanceof ClassImplementationsTreeNode) {
362 ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode) node;
363 navigateTo(classNode.getClassEntry());
364 } else if (node instanceof MethodImplementationsTreeNode) {
365 MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode) node;
366 navigateTo(methodNode.getMethodEntry());
367 }
368 }
369 }
370 });
371 JPanel implementationsPanel = new JPanel();
372 implementationsPanel.setLayout(new BorderLayout());
373 implementationsPanel.add(new JScrollPane(m_implementationsTree));
374
375 // init call panel
376 m_callsTree = new JTree();
377 m_callsTree.setModel(null);
378 m_callsTree.addMouseListener(new MouseAdapter() {
379 @SuppressWarnings("unchecked")
380 @Override
381 public void mouseClicked(MouseEvent event) {
382 if (event.getClickCount() == 2) {
383 // get the selected node
384 TreePath path = m_callsTree.getSelectionPath();
385 if (path == null) {
386 return;
387 }
388
389 Object node = path.getLastPathComponent();
390 if (node instanceof ReferenceTreeNode) {
391 ReferenceTreeNode<Entry, Entry> referenceNode = ((ReferenceTreeNode<Entry, Entry>) node);
392 if (referenceNode.getReference() != null) {
393 navigateTo(referenceNode.getReference());
394 } else {
395 navigateTo(referenceNode.getEntry());
396 }
397 }
398 }
399 }
400 });
401 m_tokens = new JList<Token>();
402 m_tokens.setCellRenderer(new TokenListCellRenderer(m_controller));
403 m_tokens.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
404 m_tokens.setLayoutOrientation(JList.VERTICAL);
405 m_tokens.addMouseListener(new MouseAdapter() {
406 @Override
407 public void mouseClicked(MouseEvent event) {
408 if (event.getClickCount() == 2) {
409 Token selected = m_tokens.getSelectedValue();
410 if (selected != null) {
411 showToken(selected);
412 }
413 }
414 }
415 });
416 m_tokens.setPreferredSize(new Dimension(0, 200));
417 m_tokens.setMinimumSize(new Dimension(0, 200));
418 JSplitPane callPanel = new JSplitPane(
419 JSplitPane.VERTICAL_SPLIT,
420 true,
421 new JScrollPane(m_callsTree),
422 new JScrollPane(m_tokens)
423 );
424 callPanel.setResizeWeight(1); // let the top side take all the slack
425 callPanel.resetToPreferredSizes();
426
427 // layout controls
428 JPanel centerPanel = new JPanel();
429 centerPanel.setLayout(new BorderLayout());
430 centerPanel.add(m_infoPanel, BorderLayout.NORTH);
431 centerPanel.add(sourceScroller, BorderLayout.CENTER);
432 m_tabs = new JTabbedPane();
433 m_tabs.setPreferredSize(new Dimension(250, 0));
434 m_tabs.addTab("Inheritance", inheritancePanel);
435 m_tabs.addTab("Implementations", implementationsPanel);
436 m_tabs.addTab("Call Graph", callPanel);
437 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs);
438 splitRight.setResizeWeight(1); // let the left side take all the slack
439 splitRight.resetToPreferredSizes();
440 JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, m_classesPanel, splitRight);
441 splitCenter.setResizeWeight(0); // let the right side take all the slack
442 pane.add(splitCenter, BorderLayout.CENTER);
443
444 // init menus
445 JMenuBar menuBar = new JMenuBar();
446 m_frame.setJMenuBar(menuBar);
447 {
448 JMenu menu = new JMenu("File");
449 menuBar.add(menu);
450 {
451 JMenuItem item = new JMenuItem("Open Jar...");
452 menu.add(item);
453 item.addActionListener(new ActionListener() {
454 @Override
455 public void actionPerformed(ActionEvent event) {
456 if (m_jarFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
457 // load the jar in a separate thread
458 new Thread() {
459 @Override
460 public void run() {
461 try {
462 m_controller.openJar(new JarFile(m_jarFileChooser.getSelectedFile()));
463 } catch (IOException ex) {
464 throw new Error(ex);
465 }
466 }
467 }.start();
468 }
469 }
470 });
471 }
472 {
473 JMenuItem item = new JMenuItem("Close Jar");
474 menu.add(item);
475 item.addActionListener(new ActionListener() {
476 @Override
477 public void actionPerformed(ActionEvent event) {
478 m_controller.closeJar();
479 }
480 });
481 m_closeJarMenu = item;
482 }
483 menu.addSeparator();
484 {
485 JMenuItem item = new JMenuItem("Open Mappings...");
486 menu.add(item);
487 item.addActionListener(new ActionListener() {
488 @Override
489 public void actionPerformed(ActionEvent event) {
490 if (m_mappingsFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
491 try {
492 m_controller.openMappings(m_mappingsFileChooser.getSelectedFile());
493 } catch (IOException ex) {
494 throw new Error(ex);
495 } catch (MappingParseException ex) {
496 JOptionPane.showMessageDialog(m_frame, ex.getMessage());
497 }
498 }
499 }
500 });
501 m_openMappingsMenu = item;
502 }
503 {
504 JMenuItem item = new JMenuItem("Open Old Mappings...");
505 menu.add(item);
506 item.addActionListener(event -> {
507 if (m_oldMappingsFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
508 try {
509 m_controller.openOldMappings(m_oldMappingsFileChooser.getSelectedFile());
510 } catch (IOException ex) {
511 throw new Error(ex);
512 } catch (MappingParseException ex) {
513 JOptionPane.showMessageDialog(m_frame, ex.getMessage());
514 }
515 }
516 });
517 m_openOldMappingsMenu = item;
518 }
519 menu.addSeparator();
520 {
521 JMenuItem item = new JMenuItem("Save Mappings");
522 menu.add(item);
523 item.addActionListener(new ActionListener() {
524 @Override
525 public void actionPerformed(ActionEvent event) {
526 try {
527 m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile());
528 } catch (IOException ex) {
529 throw new Error(ex);
530 }
531 }
532 });
533 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
534 m_saveMappingsMenu = item;
535 }
536 {
537 JMenuItem item = new JMenuItem("Save Mappings As...");
538 menu.add(item);
539 item.addActionListener(new ActionListener() {
540 @Override
541 public void actionPerformed(ActionEvent event) {
542 if (m_mappingsFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
543 try {
544 m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile());
545 m_saveMappingsMenu.setEnabled(true);
546 } catch (IOException ex) {
547 throw new Error(ex);
548 }
549 }
550 }
551 });
552 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
553 m_saveMappingsAsMenu = item;
554 }
555 {
556 JMenuItem item = new JMenuItem("Close Mappings");
557 menu.add(item);
558 item.addActionListener(new ActionListener() {
559 @Override
560 public void actionPerformed(ActionEvent event) {
561 m_controller.closeMappings();
562 }
563 });
564 m_closeMappingsMenu = item;
565 }
566 menu.addSeparator();
567 {
568 JMenuItem item = new JMenuItem("Export Source...");
569 menu.add(item);
570 item.addActionListener(new ActionListener() {
571 @Override
572 public void actionPerformed(ActionEvent event) {
573 if (m_exportSourceFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
574 m_controller.exportSource(m_exportSourceFileChooser.getSelectedFile());
575 }
576 }
577 });
578 m_exportSourceMenu = item;
579 }
580 {
581 JMenuItem item = new JMenuItem("Export Jar...");
582 menu.add(item);
583 item.addActionListener(new ActionListener() {
584 @Override
585 public void actionPerformed(ActionEvent event) {
586 if (m_exportJarFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
587 m_controller.exportJar(m_exportJarFileChooser.getSelectedFile());
588 }
589 }
590 });
591 m_exportJarMenu = item;
592 }
593 menu.addSeparator();
594 {
595 JMenuItem item = new JMenuItem("Exit");
596 menu.add(item);
597 item.addActionListener(new ActionListener() {
598 @Override
599 public void actionPerformed(ActionEvent event) {
600 close();
601 }
602 });
603 }
604 }
605 {
606 JMenu menu = new JMenu("Help");
607 menuBar.add(menu);
608 {
609 JMenuItem item = new JMenuItem("About");
610 menu.add(item);
611 item.addActionListener(new ActionListener() {
612 @Override
613 public void actionPerformed(ActionEvent event) {
614 AboutDialog.show(m_frame);
615 }
616 });
617 }
618 }
619
620 // init state
621 onCloseJar();
622
623 m_frame.addWindowListener(new WindowAdapter() {
624 @Override
625 public void windowClosing(WindowEvent event) {
626 close();
627 }
628 });
629
630 // show the frame
631 pane.doLayout();
632 m_frame.setSize(1024, 576);
633 m_frame.setMinimumSize(new Dimension(640, 480));
634 m_frame.setVisible(true);
635 m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
636 }
637
638 public JFrame getFrame() {
639 return m_frame;
640 }
641
642 public GuiController getController() {
643 return m_controller;
644 }
645
646 public void onStartOpenJar() {
647 m_classesPanel.removeAll();
648 JPanel panel = new JPanel();
649 panel.setLayout(new FlowLayout());
650 panel.add(new JLabel("Loading..."));
651 m_classesPanel.add(panel);
652 redraw();
653 }
654
655 public void onFinishOpenJar(String jarName) {
656 // update gui
657 m_frame.setTitle(Constants.Name + " - " + jarName);
658 m_classesPanel.removeAll();
659 m_classesPanel.add(m_splitClasses);
660 setSource(null);
661
662 // update menu
663 m_closeJarMenu.setEnabled(true);
664 m_openOldMappingsMenu.setEnabled(true);
665 m_openMappingsMenu.setEnabled(true);
666 m_saveMappingsMenu.setEnabled(false);
667 m_saveMappingsAsMenu.setEnabled(true);
668 m_closeMappingsMenu.setEnabled(true);
669 m_exportSourceMenu.setEnabled(true);
670 m_exportJarMenu.setEnabled(true);
671
672 redraw();
673 }
674
675 public void onCloseJar() {
676 // update gui
677 m_frame.setTitle(Constants.Name);
678 setObfClasses(null);
679 setDeobfClasses(null);
680 setSource(null);
681 m_classesPanel.removeAll();
682
683 // update menu
684 m_closeJarMenu.setEnabled(false);
685 m_openOldMappingsMenu.setEnabled(false);
686 m_openMappingsMenu.setEnabled(false);
687 m_saveMappingsMenu.setEnabled(false);
688 m_saveMappingsAsMenu.setEnabled(false);
689 m_closeMappingsMenu.setEnabled(false);
690 m_exportSourceMenu.setEnabled(false);
691 m_exportJarMenu.setEnabled(false);
692
693 redraw();
694 }
695
696 public void setObfClasses(Collection<ClassEntry> obfClasses) {
697 m_obfClasses.setClasses(obfClasses);
698 }
699
700 public void setDeobfClasses(Collection<ClassEntry> deobfClasses) {
701 m_deobfClasses.setClasses(deobfClasses);
702 }
703
704 public void setMappingsFile(File file) {
705 m_mappingsFileChooser.setSelectedFile(file);
706 m_saveMappingsMenu.setEnabled(file != null);
707 }
708
709 public void setSource(String source) {
710 m_editor.getHighlighter().removeAllHighlights();
711 m_editor.setText(source);
712 }
713
714 public void showToken(final Token token) {
715 if (token == null) {
716 throw new IllegalArgumentException("Token cannot be null!");
717 }
718 CodeReader.navigateToToken(m_editor, token, m_selectionHighlightPainter);
719 redraw();
720 }
721
722 public void showTokens(Collection<Token> tokens) {
723 Vector<Token> sortedTokens = new Vector<Token>(tokens);
724 Collections.sort(sortedTokens);
725 if (sortedTokens.size() > 1) {
726 // sort the tokens and update the tokens panel
727 m_tokens.setListData(sortedTokens);
728 m_tokens.setSelectedIndex(0);
729 } else {
730 m_tokens.setListData(new Vector<Token>());
731 }
732
733 // show the first token
734 showToken(sortedTokens.get(0));
735 }
736
737 public void setHighlightedTokens(Iterable<Token> obfuscatedTokens, Iterable<Token> deobfuscatedTokens, Iterable<Token> otherTokens) {
738
739 // remove any old highlighters
740 m_editor.getHighlighter().removeAllHighlights();
741
742 // color things based on the index
743 if (obfuscatedTokens != null) {
744 setHighlightedTokens(obfuscatedTokens, m_obfuscatedHighlightPainter);
745 }
746 if (deobfuscatedTokens != null) {
747 setHighlightedTokens(deobfuscatedTokens, m_deobfuscatedHighlightPainter);
748 }
749 if (otherTokens != null) {
750 setHighlightedTokens(otherTokens, m_otherHighlightPainter);
751 }
752
753 redraw();
754 }
755
756 private void setHighlightedTokens(Iterable<Token> tokens, Highlighter.HighlightPainter painter) {
757 for (Token token : tokens) {
758 try {
759 m_editor.getHighlighter().addHighlight(token.start, token.end, painter);
760 } catch (BadLocationException ex) {
761 throw new IllegalArgumentException(ex);
762 }
763 }
764 }
765
766 private void clearReference() {
767 m_infoPanel.removeAll();
768 JLabel label = new JLabel("No identifier selected");
769 GuiTricks.unboldLabel(label);
770 label.setHorizontalAlignment(JLabel.CENTER);
771 m_infoPanel.add(label);
772
773 redraw();
774 }
775
776 private void showReference(EntryReference<Entry, Entry> reference) {
777 if (reference == null) {
778 clearReference();
779 return;
780 }
781
782 m_reference = reference;
783
784 m_infoPanel.removeAll();
785 if (reference.entry instanceof ClassEntry) {
786 showClassEntry((ClassEntry) m_reference.entry);
787 } else if (m_reference.entry instanceof FieldEntry) {
788 showFieldEntry((FieldEntry) m_reference.entry);
789 } else if (m_reference.entry instanceof MethodEntry) {
790 showMethodEntry((MethodEntry) m_reference.entry);
791 } else if (m_reference.entry instanceof ConstructorEntry) {
792 showConstructorEntry((ConstructorEntry) m_reference.entry);
793 } else if (m_reference.entry instanceof ArgumentEntry) {
794 showArgumentEntry((ArgumentEntry) m_reference.entry);
795 } else {
796 throw new Error("Unknown entry type: " + m_reference.entry.getClass().getName());
797 }
798
799 redraw();
800 }
801
802 private void showClassEntry(ClassEntry entry) {
803 addNameValue(m_infoPanel, "Class", entry.getName());
804 }
805
806 private void showFieldEntry(FieldEntry entry) {
807 addNameValue(m_infoPanel, "Field", entry.getName());
808 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
809 addNameValue(m_infoPanel, "Type", entry.getType().toString());
810 }
811
812 private void showMethodEntry(MethodEntry entry) {
813 addNameValue(m_infoPanel, "Method", entry.getName());
814 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
815 addNameValue(m_infoPanel, "Signature", entry.getSignature().toString());
816 }
817
818 private void showConstructorEntry(ConstructorEntry entry) {
819 addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName());
820 if (!entry.isStatic()) {
821 addNameValue(m_infoPanel, "Signature", entry.getSignature().toString());
822 }
823 }
824
825 private void showArgumentEntry(ArgumentEntry entry) {
826 addNameValue(m_infoPanel, "Argument", entry.getName());
827 addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName());
828 addNameValue(m_infoPanel, "Method", entry.getBehaviorEntry().getName());
829 addNameValue(m_infoPanel, "Index", Integer.toString(entry.getIndex()));
830 }
831
832 private void addNameValue(JPanel container, String name, String value) {
833 JPanel panel = new JPanel();
834 panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0));
835 container.add(panel);
836
837 JLabel label = new JLabel(name + ":", JLabel.RIGHT);
838 label.setPreferredSize(new Dimension(100, label.getPreferredSize().height));
839 panel.add(label);
840
841 panel.add(GuiTricks.unboldLabel(new JLabel(value, JLabel.LEFT)));
842 }
843
844 private void onCaretMove(int pos) {
845
846 Token token = m_controller.getToken(pos);
847 boolean isToken = token != null;
848
849 m_reference = m_controller.getDeobfReference(token);
850 boolean isClassEntry = isToken && m_reference.entry instanceof ClassEntry;
851 boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry;
852 boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry;
853 boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry;
854 boolean isInJar = isToken && m_controller.entryIsInJar(m_reference.entry);
855 boolean isRenameable = isToken && m_controller.referenceIsRenameable(m_reference);
856
857 if (isToken) {
858 showReference(m_reference);
859 } else {
860 clearReference();
861 }
862
863 m_renameMenu.setEnabled(isRenameable && isToken);
864 m_showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry);
865 m_showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry);
866 m_showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry);
867 m_openEntryMenu.setEnabled(isInJar && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry));
868 m_openPreviousMenu.setEnabled(m_controller.hasPreviousLocation());
869 m_toggleMappingMenu.setEnabled(isRenameable && isToken);
870
871 if (isToken && m_controller.entryHasDeobfuscatedName(m_reference.entry)) {
872 m_toggleMappingMenu.setText("Reset to obfuscated");
873 } else {
874 m_toggleMappingMenu.setText("Mark as deobfuscated");
875 }
876 }
877
878 private void navigateTo(Entry entry) {
879 if (!m_controller.entryIsInJar(entry)) {
880 // entry is not in the jar. Ignore it
881 return;
882 }
883 if (m_reference != null) {
884 m_controller.savePreviousReference(m_reference);
885 }
886 m_controller.openDeclaration(entry);
887 }
888
889 private void navigateTo(EntryReference<Entry, Entry> reference) {
890 if (!m_controller.entryIsInJar(reference.getLocationClassEntry())) {
891 // reference is not in the jar. Ignore it
892 return;
893 }
894 if (m_reference != null) {
895 m_controller.savePreviousReference(m_reference);
896 }
897 m_controller.openReference(reference);
898 }
899
900 private void startRename() {
901
902 // init the text box
903 final JTextField text = new JTextField();
904 text.setText(m_reference.getNamableName());
905 text.setPreferredSize(new Dimension(360, text.getPreferredSize().height));
906 text.addKeyListener(new KeyAdapter() {
907 @Override
908 public void keyPressed(KeyEvent event) {
909 switch (event.getKeyCode()) {
910 case KeyEvent.VK_ENTER:
911 finishRename(text, true);
912 break;
913
914 case KeyEvent.VK_ESCAPE:
915 finishRename(text, false);
916 break;
917 }
918 }
919 });
920
921 // find the label with the name and replace it with the text box
922 JPanel panel = (JPanel) m_infoPanel.getComponent(0);
923 panel.remove(panel.getComponentCount() - 1);
924 panel.add(text);
925 text.grabFocus();
926 text.selectAll();
927
928 redraw();
929 }
930
931 private void finishRename(JTextField text, boolean saveName) {
932 String newName = text.getText();
933 if (saveName && newName != null && newName.length() > 0) {
934 try {
935 m_controller.rename(m_reference, newName);
936 } catch (IllegalNameException ex) {
937 text.setBorder(BorderFactory.createLineBorder(Color.red, 1));
938 text.setToolTipText(ex.getReason());
939 GuiTricks.showToolTipNow(text);
940 }
941 return;
942 }
943
944 // abort the rename
945 JPanel panel = (JPanel) m_infoPanel.getComponent(0);
946 panel.remove(panel.getComponentCount() - 1);
947 panel.add(GuiTricks.unboldLabel(new JLabel(m_reference.getNamableName(), JLabel.LEFT)));
948
949 m_editor.grabFocus();
950
951 redraw();
952 }
953
954 private void showInheritance() {
955
956 if (m_reference == null) {
957 return;
958 }
959
960 m_inheritanceTree.setModel(null);
961
962 if (m_reference.entry instanceof ClassEntry) {
963 // get the class inheritance
964 ClassInheritanceTreeNode classNode = m_controller.getClassInheritance((ClassEntry) m_reference.entry);
965
966 // show the tree at the root
967 TreePath path = getPathToRoot(classNode);
968 m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
969 m_inheritanceTree.expandPath(path);
970 m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path));
971 } else if (m_reference.entry instanceof MethodEntry) {
972 // get the method inheritance
973 MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance((MethodEntry) m_reference.entry);
974
975 // show the tree at the root
976 TreePath path = getPathToRoot(classNode);
977 m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
978 m_inheritanceTree.expandPath(path);
979 m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path));
980 }
981
982 m_tabs.setSelectedIndex(0);
983 redraw();
984 }
985
986 private void showImplementations() {
987
988 if (m_reference == null) {
989 return;
990 }
991
992 m_implementationsTree.setModel(null);
993
994 if (m_reference.entry instanceof ClassEntry) {
995 // get the class implementations
996 ClassImplementationsTreeNode node = m_controller.getClassImplementations((ClassEntry) m_reference.entry);
997 if (node != null) {
998 // show the tree at the root
999 TreePath path = getPathToRoot(node);
1000 m_implementationsTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
1001 m_implementationsTree.expandPath(path);
1002 m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path));
1003 }
1004 } else if (m_reference.entry instanceof MethodEntry) {
1005 // get the method implementations
1006 MethodImplementationsTreeNode node = m_controller.getMethodImplementations((MethodEntry) m_reference.entry);
1007 if (node != null) {
1008 // show the tree at the root
1009 TreePath path = getPathToRoot(node);
1010 m_implementationsTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0)));
1011 m_implementationsTree.expandPath(path);
1012 m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path));
1013 }
1014 }
1015
1016 m_tabs.setSelectedIndex(1);
1017 redraw();
1018 }
1019
1020 private void showCalls() {
1021
1022 if (m_reference == null) {
1023 return;
1024 }
1025
1026 if (m_reference.entry instanceof ClassEntry) {
1027 // look for calls to the default constructor
1028 // TODO: get a list of all the constructors and find calls to all of them
1029 BehaviorReferenceTreeNode node = m_controller.getMethodReferences(new ConstructorEntry((ClassEntry) m_reference.entry, new Signature("()V")));
1030 m_callsTree.setModel(new DefaultTreeModel(node));
1031 } else if (m_reference.entry instanceof FieldEntry) {
1032 FieldReferenceTreeNode node = m_controller.getFieldReferences((FieldEntry) m_reference.entry);
1033 m_callsTree.setModel(new DefaultTreeModel(node));
1034 } else if (m_reference.entry instanceof MethodEntry) {
1035 BehaviorReferenceTreeNode node = m_controller.getMethodReferences((MethodEntry) m_reference.entry);
1036 m_callsTree.setModel(new DefaultTreeModel(node));
1037 } else if (m_reference.entry instanceof ConstructorEntry) {
1038 BehaviorReferenceTreeNode node = m_controller.getMethodReferences((ConstructorEntry) m_reference.entry);
1039 m_callsTree.setModel(new DefaultTreeModel(node));
1040 }
1041
1042 m_tabs.setSelectedIndex(2);
1043 redraw();
1044 }
1045
1046 private void toggleMapping() {
1047 if (m_controller.entryHasDeobfuscatedName(m_reference.entry)) {
1048 m_controller.removeMapping(m_reference);
1049 } else {
1050 m_controller.markAsDeobfuscated(m_reference);
1051 }
1052 }
1053
1054 private TreePath getPathToRoot(TreeNode node) {
1055 List<TreeNode> nodes = Lists.newArrayList();
1056 TreeNode n = node;
1057 do {
1058 nodes.add(n);
1059 n = n.getParent();
1060 } while (n != null);
1061 Collections.reverse(nodes);
1062 return new TreePath(nodes.toArray());
1063 }
1064
1065 private void close() {
1066 if (!m_controller.isDirty()) {
1067 // everything is saved, we can exit safely
1068 m_frame.dispose();
1069 } else {
1070 // ask to save before closing
1071 String[] options = {"Save and exit", "Discard changes", "Cancel"};
1072 int response = JOptionPane.showOptionDialog(m_frame, "Your mappings have not been saved yet. Do you want to save?", "Save your changes?", JOptionPane.YES_NO_CANCEL_OPTION,
1073 JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
1074 switch (response) {
1075 case JOptionPane.YES_OPTION: // save and exit
1076 if (m_mappingsFileChooser.getSelectedFile() != null || m_mappingsFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) {
1077 try {
1078 m_controller.saveMappings(m_mappingsFileChooser.getCurrentDirectory());
1079 m_frame.dispose();
1080 } catch (IOException ex) {
1081 throw new Error(ex);
1082 }
1083 }
1084 break;
1085
1086 case JOptionPane.NO_OPTION:
1087 // don't save, exit
1088 m_frame.dispose();
1089 break;
1090
1091 // cancel means do nothing
1092 }
1093 }
1094 }
1095
1096 private void redraw() {
1097 m_frame.validate();
1098 m_frame.repaint();
1099 }
1100}