diff options
| author | 2016-06-30 00:49:21 +1000 | |
|---|---|---|
| committer | 2016-06-30 00:49:21 +1000 | |
| commit | 4be005617b3b8c3578cca07c5d085d12916f0d1d (patch) | |
| tree | db163431f38703e26da417ef05eaea2b27a498b9 /src/main/java/cuchaz/enigma/gui/Gui.java | |
| parent | Some small changes to fix idea importing (diff) | |
| download | enigma-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.java | 1100 |
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 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.gui; | ||
| 12 | |||
| 13 | import com.google.common.collect.Lists; | ||
| 14 | |||
| 15 | import java.awt.*; | ||
| 16 | import java.awt.event.*; | ||
| 17 | import java.io.File; | ||
| 18 | import java.io.IOException; | ||
| 19 | import java.lang.Thread.UncaughtExceptionHandler; | ||
| 20 | import java.util.Collection; | ||
| 21 | import java.util.Collections; | ||
| 22 | import java.util.List; | ||
| 23 | import java.util.Vector; | ||
| 24 | import java.util.jar.JarFile; | ||
| 25 | |||
| 26 | import javax.swing.*; | ||
| 27 | import javax.swing.event.CaretEvent; | ||
| 28 | import javax.swing.event.CaretListener; | ||
| 29 | import javax.swing.text.BadLocationException; | ||
| 30 | import javax.swing.text.Highlighter; | ||
| 31 | import javax.swing.tree.DefaultTreeModel; | ||
| 32 | import javax.swing.tree.TreeNode; | ||
| 33 | import javax.swing.tree.TreePath; | ||
| 34 | |||
| 35 | import cuchaz.enigma.Constants; | ||
| 36 | import cuchaz.enigma.ExceptionIgnorer; | ||
| 37 | import cuchaz.enigma.analysis.*; | ||
| 38 | import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; | ||
| 39 | import cuchaz.enigma.mapping.*; | ||
| 40 | import de.sciss.syntaxpane.DefaultSyntaxKit; | ||
| 41 | |||
| 42 | public 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 | } | ||