From 52c1aeede3a59e81bd16c8a4ccf63bb0d6e7ba12 Mon Sep 17 00:00:00 2001 From: 2xsaiko Date: Sun, 7 Jun 2020 15:52:24 +0200 Subject: No more prefix naming --- .../src/main/java/cuchaz/enigma/gui/Gui.java | 94 +-- .../enigma/gui/elements/EditorTabPopupMenu.java | 8 +- .../cuchaz/enigma/gui/elements/PopupMenuBar.java | 16 +- .../enigma/gui/events/EditorActionListener.java | 8 +- .../enigma/gui/filechooser/FileChooserAny.java | 10 - .../enigma/gui/filechooser/FileChooserFile.java | 8 - .../enigma/gui/filechooser/FileChooserFolder.java | 11 - .../java/cuchaz/enigma/gui/panels/DeobfPanel.java | 29 + .../java/cuchaz/enigma/gui/panels/EditorPanel.java | 666 +++++++++++++++++++++ .../cuchaz/enigma/gui/panels/IdentifierPanel.java | 255 ++++++++ .../java/cuchaz/enigma/gui/panels/ObfPanel.java | 40 ++ .../java/cuchaz/enigma/gui/panels/PanelDeobf.java | 26 - .../java/cuchaz/enigma/gui/panels/PanelEditor.java | 666 --------------------- .../cuchaz/enigma/gui/panels/PanelIdentifier.java | 255 -------- .../java/cuchaz/enigma/gui/panels/PanelObf.java | 37 -- 15 files changed, 1058 insertions(+), 1071 deletions(-) delete mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserAny.java delete mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFile.java delete mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java create mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java create mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java create mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java create mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java delete mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java delete mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java delete mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java delete mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java (limited to 'enigma-swing/src/main/java') diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index 2ac1528..0b2de46 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java @@ -26,6 +26,7 @@ import javax.swing.tree.*; import com.google.common.collect.HashBiMap; import com.google.common.collect.Lists; + import cuchaz.enigma.Enigma; import cuchaz.enigma.EnigmaProfile; import cuchaz.enigma.analysis.*; @@ -40,8 +41,6 @@ import cuchaz.enigma.gui.elements.EditorTabPopupMenu; import cuchaz.enigma.gui.elements.MenuBar; import cuchaz.enigma.gui.elements.ValidatableUi; import cuchaz.enigma.gui.events.EditorActionListener; -import cuchaz.enigma.gui.filechooser.FileChooserAny; -import cuchaz.enigma.gui.filechooser.FileChooserFolder; import cuchaz.enigma.gui.panels.*; import cuchaz.enigma.gui.util.History; import cuchaz.enigma.gui.util.ScaleUtil; @@ -62,8 +61,8 @@ import cuchaz.enigma.utils.validation.ValidationContext; public class Gui { - private final PanelObf obfPanel; - private final PanelDeobf deobfPanel; + private final ObfPanel obfPanel; + private final DeobfPanel deobfPanel; private final MenuBar menuBar; @@ -82,7 +81,7 @@ public class Gui { private JFrame frame; private JPanel classesPanel; private JSplitPane splitClasses; - private PanelIdentifier infoPanel; + private IdentifierPanel infoPanel; private JTree inheritanceTree; private JTree implementationsTree; private JTree callsTree; @@ -105,7 +104,7 @@ public class Gui { private final EditorTabPopupMenu editorTabPopupMenu; private final JTabbedPane openFiles; - private final HashBiMap editors = HashBiMap.create(); + private final HashBiMap editors = HashBiMap.create(); public Gui(EnigmaProfile profile) { Config.getInstance().lookAndFeel.setGlobalLAF(); @@ -138,12 +137,19 @@ public class Gui { this.jarFileChooser = new FileDialog(getFrame(), I18n.translate("menu.file.jar.open"), FileDialog.LOAD); this.tinyMappingsFileChooser = new FileDialog(getFrame(), "Open tiny Mappings", FileDialog.LOAD); - this.enigmaMappingsFileChooser = new FileChooserAny(); - this.exportSourceFileChooser = new FileChooserFolder(); + + this.enigmaMappingsFileChooser = new JFileChooser(); + this.enigmaMappingsFileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); + this.enigmaMappingsFileChooser.setAcceptAllFileFilterUsed(false); + + this.exportSourceFileChooser = new JFileChooser(); + this.exportSourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + this.exportSourceFileChooser.setAcceptAllFileFilterUsed(false); + this.exportJarFileChooser = new FileDialog(getFrame(), I18n.translate("menu.file.export.jar"), FileDialog.SAVE); - this.obfPanel = new PanelObf(this); - this.deobfPanel = new PanelDeobf(this); + this.obfPanel = new ObfPanel(this); + this.deobfPanel = new DeobfPanel(this); // set up classes panel (don't add the splitter yet) splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, this.obfPanel, this.deobfPanel); @@ -153,7 +159,7 @@ public class Gui { this.classesPanel.setPreferredSize(ScaleUtil.getDimension(250, 0)); // init info panel - infoPanel = new PanelIdentifier(this); + infoPanel = new IdentifierPanel(this); // init inheritance panel inheritanceTree = new JTree(); @@ -276,7 +282,7 @@ public class Gui { if (SwingUtilities.isRightMouseButton(e)) { int i = openFiles.getUI().tabForCoordinate(openFiles, e.getX(), e.getY()); if (i != -1) { - editorTabPopupMenu.show(openFiles, e.getX(), e.getY(), PanelEditor.byUi(openFiles.getComponentAt(i))); + editorTabPopupMenu.show(openFiles, e.getX(), e.getY(), EditorPanel.byUi(openFiles.getComponentAt(i))); } } } @@ -403,11 +409,11 @@ public class Gui { redraw(); } - public PanelEditor openClass(ClassEntry entry) { - PanelEditor panelEditor = editors.computeIfAbsent(entry, e -> { + public EditorPanel openClass(ClassEntry entry) { + EditorPanel editorPanel = editors.computeIfAbsent(entry, e -> { ClassHandle ch = controller.getClassHandleProvider().openClass(entry); if (ch == null) return null; - PanelEditor ed = new PanelEditor(this); + EditorPanel ed = new EditorPanel(this); ed.setup(); ed.setClassHandle(ch); openFiles.addTab(ed.getFileName(), ed.getUi()); @@ -418,18 +424,18 @@ public class Gui { ed.addListener(new EditorActionListener() { @Override - public void onCursorReferenceChanged(PanelEditor editor, EntryReference, Entry> ref) { + public void onCursorReferenceChanged(EditorPanel editor, EntryReference, Entry> ref) { updateSelectedReference(editor, ref); } @Override - public void onClassHandleChanged(PanelEditor editor, ClassEntry old, ClassHandle ch) { + public void onClassHandleChanged(EditorPanel editor, ClassEntry old, ClassHandle ch) { editors.remove(old); editors.put(ch.getRef(), editor); } @Override - public void onTitleChanged(PanelEditor editor, String title) { + public void onTitleChanged(EditorPanel editor, String title) { titlePane.setText(editor.getFileName()); } }); @@ -445,10 +451,10 @@ public class Gui { return ed; }); - if (panelEditor != null) { + if (editorPanel != null) { openFiles.setSelectedComponent(editors.get(entry).getUi()); } - return panelEditor; + return editorPanel; } public void setObfClasses(Collection obfClasses) { @@ -464,44 +470,44 @@ public class Gui { updateUiState(); } - public void closeEditor(PanelEditor ed) { + public void closeEditor(EditorPanel ed) { openFiles.remove(ed.getUi()); editors.inverse().remove(ed); ed.destroy(); } public void closeAllEditorTabs() { - for (Iterator iter = editors.values().iterator(); iter.hasNext(); ) { - PanelEditor e = iter.next(); + for (Iterator iter = editors.values().iterator(); iter.hasNext(); ) { + EditorPanel e = iter.next(); openFiles.remove(e.getUi()); e.destroy(); iter.remove(); } } - public void closeTabsLeftOf(PanelEditor ed) { + public void closeTabsLeftOf(EditorPanel ed) { int index = openFiles.indexOfComponent(ed.getUi()); for (int i = index - 1; i >= 0; i--) { - closeEditor(PanelEditor.byUi(openFiles.getComponentAt(i))); + closeEditor(EditorPanel.byUi(openFiles.getComponentAt(i))); } } - public void closeTabsRightOf(PanelEditor ed) { + public void closeTabsRightOf(EditorPanel ed) { int index = openFiles.indexOfComponent(ed.getUi()); for (int i = openFiles.getTabCount() - 1; i > index; i--) { - closeEditor(PanelEditor.byUi(openFiles.getComponentAt(i))); + closeEditor(EditorPanel.byUi(openFiles.getComponentAt(i))); } } - public void closeTabsExcept(PanelEditor ed) { + public void closeTabsExcept(EditorPanel ed) { int index = openFiles.indexOfComponent(ed.getUi()); for (int i = openFiles.getTabCount() - 1; i >= 0; i--) { if (i == index) continue; - closeEditor(PanelEditor.byUi(openFiles.getComponentAt(i))); + closeEditor(EditorPanel.byUi(openFiles.getComponentAt(i))); } } - public void showTokens(PanelEditor editor, Collection tokens) { + public void showTokens(EditorPanel editor, Collection tokens) { Vector sortedTokens = new Vector<>(tokens); Collections.sort(sortedTokens); if (sortedTokens.size() > 1) { @@ -517,7 +523,7 @@ public class Gui { editor.navigateToToken(sortedTokens.get(0)); } - private void updateSelectedReference(PanelEditor editor, EntryReference, Entry> ref) { + private void updateSelectedReference(EditorPanel editor, EntryReference, Entry> ref) { if (editor != getActiveEditor()) return; showCursorReference(ref); @@ -528,35 +534,35 @@ public class Gui { } @Nullable - public PanelEditor getActiveEditor() { - return PanelEditor.byUi(openFiles.getSelectedComponent()); + public EditorPanel getActiveEditor() { + return EditorPanel.byUi(openFiles.getSelectedComponent()); } @Nullable public EntryReference, Entry> getCursorReference() { - PanelEditor activeEditor = getActiveEditor(); + EditorPanel activeEditor = getActiveEditor(); return activeEditor == null ? null : activeEditor.getCursorReference(); } - public void startDocChange(PanelEditor editor) { + public void startDocChange(EditorPanel editor) { EntryReference, Entry> cursorReference = editor.getCursorReference(); if (cursorReference == null) return; JavadocDialog.show(frame, getController(), cursorReference); } - public void startRename(PanelEditor editor, String text) { + public void startRename(EditorPanel editor, String text) { if (editor != getActiveEditor()) return; infoPanel.startRenaming(text); } - public void startRename(PanelEditor editor) { + public void startRename(EditorPanel editor) { if (editor != getActiveEditor()) return; infoPanel.startRenaming(); } - public void showInheritance(PanelEditor editor) { + public void showInheritance(EditorPanel editor) { EntryReference, Entry> cursorReference = editor.getCursorReference(); if (cursorReference == null) return; @@ -587,7 +593,7 @@ public class Gui { redraw(); } - public void showImplementations(PanelEditor editor) { + public void showImplementations(EditorPanel editor) { EntryReference, Entry> cursorReference = editor.getCursorReference(); if (cursorReference == null) return; @@ -615,7 +621,7 @@ public class Gui { redraw(); } - public void showCalls(PanelEditor editor, boolean recurse) { + public void showCalls(EditorPanel editor, boolean recurse) { EntryReference, Entry> cursorReference = editor.getCursorReference(); if (cursorReference == null) return; @@ -635,7 +641,7 @@ public class Gui { redraw(); } - public void toggleMapping(PanelEditor editor) { + public void toggleMapping(EditorPanel editor) { EntryReference, Entry> cursorReference = editor.getCursorReference(); if (cursorReference == null) return; @@ -781,11 +787,11 @@ public class Gui { this.obfPanel.obfClasses.restoreExpansionState(this.obfPanel.obfClasses, stateObf); } - public PanelObf getObfPanel() { + public ObfPanel getObfPanel() { return obfPanel; } - public PanelDeobf getDeobfPanel() { + public DeobfPanel getDeobfPanel() { return deobfPanel; } @@ -858,7 +864,7 @@ public class Gui { return this.connectionState; } - public PanelIdentifier getInfoPanel() { + public IdentifierPanel getInfoPanel() { return infoPanel; } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java index e92e677..39ed978 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java @@ -8,7 +8,7 @@ import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.gui.panels.PanelEditor; +import cuchaz.enigma.gui.panels.EditorPanel; import cuchaz.enigma.utils.I18n; public class EditorTabPopupMenu { @@ -21,7 +21,7 @@ public class EditorTabPopupMenu { private final JMenuItem closeRight; private final Gui gui; - private PanelEditor editor; + private EditorPanel editor; public EditorTabPopupMenu(Gui gui) { this.gui = gui; @@ -50,8 +50,8 @@ public class EditorTabPopupMenu { this.ui.add(this.closeRight); } - public void show(Component invoker, int x, int y, PanelEditor panelEditor) { - this.editor = panelEditor; + public void show(Component invoker, int x, int y, EditorPanel editorPanel) { + this.editor = editorPanel; ui.show(invoker, x, y); } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java index 2310cf3..ad6dac6 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/PopupMenuBar.java @@ -1,13 +1,17 @@ package cuchaz.enigma.gui.elements; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.gui.panels.PanelEditor; -import cuchaz.enigma.utils.I18n; - -import javax.swing.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; +import javax.swing.KeyStroke; + +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.gui.panels.EditorPanel; +import cuchaz.enigma.utils.I18n; + public class PopupMenuBar extends JPopupMenu { public final JMenuItem renameMenu; @@ -21,7 +25,7 @@ public class PopupMenuBar extends JPopupMenu { public final JMenuItem openNextMenu; public final JMenuItem toggleMappingMenu; - public PopupMenuBar(PanelEditor editor, Gui gui) { + public PopupMenuBar(EditorPanel editor, Gui gui) { { JMenuItem menu = new JMenuItem(I18n.translate("popup_menu.rename")); menu.addActionListener(event -> gui.startRename(editor)); diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java index 8880731..48c9ec4 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java @@ -1,20 +1,20 @@ package cuchaz.enigma.gui.events; import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.gui.panels.PanelEditor; import cuchaz.enigma.classhandle.ClassHandle; +import cuchaz.enigma.gui.panels.EditorPanel; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.translation.representation.entry.Entry; public interface EditorActionListener { - default void onCursorReferenceChanged(PanelEditor editor, EntryReference, Entry> ref) { + default void onCursorReferenceChanged(EditorPanel editor, EntryReference, Entry> ref) { } - default void onClassHandleChanged(PanelEditor editor, ClassEntry old, ClassHandle ch) { + default void onClassHandleChanged(EditorPanel editor, ClassEntry old, ClassHandle ch) { } - default void onTitleChanged(PanelEditor editor, String title) { + default void onTitleChanged(EditorPanel editor, String title) { } } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserAny.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserAny.java deleted file mode 100644 index f5f6628..0000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserAny.java +++ /dev/null @@ -1,10 +0,0 @@ -package cuchaz.enigma.gui.filechooser; - -import javax.swing.*; - -public class FileChooserAny extends JFileChooser { - public FileChooserAny() { - this.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - this.setAcceptAllFileFilterUsed(false); - } -} \ No newline at end of file diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFile.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFile.java deleted file mode 100644 index cea11a6..0000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFile.java +++ /dev/null @@ -1,8 +0,0 @@ -package cuchaz.enigma.gui.filechooser; - -import javax.swing.*; - -public class FileChooserFile extends JFileChooser { - public FileChooserFile() { - } -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java deleted file mode 100644 index c16e0af..0000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java +++ /dev/null @@ -1,11 +0,0 @@ -package cuchaz.enigma.gui.filechooser; - -import javax.swing.*; - -public class FileChooserFolder extends JFileChooser { - - public FileChooserFolder() { - this.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - this.setAcceptAllFileFilterUsed(false); - } -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java new file mode 100644 index 0000000..bb8acc8 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java @@ -0,0 +1,29 @@ +package cuchaz.enigma.gui.panels; + +import java.awt.BorderLayout; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import cuchaz.enigma.gui.ClassSelector; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.utils.I18n; + +public class DeobfPanel extends JPanel { + + public final ClassSelector deobfClasses; + private final Gui gui; + + public DeobfPanel(Gui gui) { + this.gui = gui; + + this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); + this.deobfClasses.setSelectionListener(gui.getController()::navigateTo); + this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); + + this.setLayout(new BorderLayout()); + this.add(new JLabel(I18n.translate("info_panel.classes.deobfuscated")), BorderLayout.NORTH); + this.add(new JScrollPane(this.deobfClasses), BorderLayout.CENTER); + } +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java new file mode 100644 index 0000000..f689a21 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java @@ -0,0 +1,666 @@ +package cuchaz.enigma.gui.panels; + +import java.awt.*; +import java.awt.event.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.swing.*; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Highlighter; +import javax.swing.text.Highlighter.HighlightPainter; + +import de.sciss.syntaxpane.DefaultSyntaxKit; + +import cuchaz.enigma.EnigmaProject; +import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.classhandle.ClassHandle; +import cuchaz.enigma.classhandle.ClassHandleError; +import cuchaz.enigma.events.ClassHandleListener; +import cuchaz.enigma.gui.BrowserCaret; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.gui.GuiController; +import cuchaz.enigma.gui.config.Config; +import cuchaz.enigma.gui.config.Themes; +import cuchaz.enigma.gui.elements.PopupMenuBar; +import cuchaz.enigma.gui.events.EditorActionListener; +import cuchaz.enigma.gui.events.ThemeChangeListener; +import cuchaz.enigma.gui.highlight.BoxHighlightPainter; +import cuchaz.enigma.gui.highlight.SelectionHighlightPainter; +import cuchaz.enigma.gui.util.ScaleUtil; +import cuchaz.enigma.source.DecompiledClassSource; +import cuchaz.enigma.source.RenamableTokenType; +import cuchaz.enigma.source.Token; +import cuchaz.enigma.translation.mapping.EntryRemapper; +import cuchaz.enigma.translation.mapping.EntryResolver; +import cuchaz.enigma.translation.mapping.ResolutionStrategy; +import cuchaz.enigma.translation.representation.entry.ClassEntry; +import cuchaz.enigma.translation.representation.entry.Entry; +import cuchaz.enigma.translation.representation.entry.FieldEntry; +import cuchaz.enigma.translation.representation.entry.MethodEntry; +import cuchaz.enigma.utils.I18n; +import cuchaz.enigma.utils.Result; + +public class EditorPanel { + + private final JPanel ui = new JPanel(); + private final JEditorPane editor = new JEditorPane(); + private final JScrollPane editorScrollPane = new JScrollPane(this.editor); + private final PopupMenuBar popupMenu; + + // progress UI + private final JLabel decompilingLabel = new JLabel(I18n.translate("editor.decompiling"), JLabel.CENTER); + private final JProgressBar decompilingProgressBar = new JProgressBar(0, 100); + + // error display UI + private final JLabel errorLabel = new JLabel(); + private final JTextArea errorTextArea = new JTextArea(); + private final JScrollPane errorScrollPane = new JScrollPane(this.errorTextArea); + private final JButton retryButton = new JButton(I18n.translate("general.retry")); + + private DisplayMode mode = DisplayMode.INACTIVE; + + private final GuiController controller; + private final Gui gui; + + private EntryReference, Entry> cursorReference; + private boolean mouseIsPressed = false; + private boolean shouldNavigateOnClick; + + public Config.LookAndFeel editorLaf; + private int fontSize = 12; + private Map boxHighlightPainters; + + private final List listeners = new ArrayList<>(); + + private final ThemeChangeListener themeChangeListener; + + private ClassHandle classHandle; + private DecompiledClassSource source; + private boolean settingSource; + + public EditorPanel(Gui gui) { + this.gui = gui; + this.controller = gui.getController(); + + this.editor.setEditable(false); + this.editor.setSelectionColor(new Color(31, 46, 90)); + this.editor.setCaret(new BrowserCaret()); + this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); + this.editor.addCaretListener(event -> onCaretMove(event.getDot(), this.mouseIsPressed)); + this.editor.setCaretColor(new Color(Config.getInstance().caretColor)); + this.editor.setContentType("text/enigma-sources"); + this.editor.setBackground(new Color(Config.getInstance().editorBackground)); + DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); + kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker"); + + // init editor popup menu + this.popupMenu = new PopupMenuBar(this, gui); + this.editor.setComponentPopupMenu(this.popupMenu); + + this.decompilingLabel.setFont(ScaleUtil.getFont(this.decompilingLabel.getFont().getFontName(), Font.BOLD, 26)); + this.decompilingProgressBar.setIndeterminate(true); + this.errorTextArea.setEditable(false); + this.errorTextArea.setFont(ScaleUtil.getFont(Font.MONOSPACED, Font.PLAIN, 10)); + + this.boxHighlightPainters = Themes.getBoxHighlightPainters(); + + this.editor.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent mouseEvent) { + EditorPanel.this.mouseIsPressed = true; + } + + @Override + public void mouseReleased(MouseEvent e) { + switch (e.getButton()) { + case MouseEvent.BUTTON3: // Right click + EditorPanel.this.editor.setCaretPosition(EditorPanel.this.editor.viewToModel(e.getPoint())); + break; + + case 4: // Back navigation + gui.getController().openPreviousReference(); + break; + + case 5: // Forward navigation + gui.getController().openNextReference(); + break; + } + EditorPanel.this.mouseIsPressed = false; + } + }); + this.editor.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent event) { + if (event.isControlDown()) { + EditorPanel.this.shouldNavigateOnClick = false; + switch (event.getKeyCode()) { + case KeyEvent.VK_I: + EditorPanel.this.popupMenu.showInheritanceMenu.doClick(); + break; + + case KeyEvent.VK_M: + EditorPanel.this.popupMenu.showImplementationsMenu.doClick(); + break; + + case KeyEvent.VK_N: + EditorPanel.this.popupMenu.openEntryMenu.doClick(); + break; + + case KeyEvent.VK_P: + EditorPanel.this.popupMenu.openPreviousMenu.doClick(); + break; + + case KeyEvent.VK_E: + EditorPanel.this.popupMenu.openNextMenu.doClick(); + break; + + case KeyEvent.VK_C: + if (event.isShiftDown()) { + EditorPanel.this.popupMenu.showCallsSpecificMenu.doClick(); + } else { + EditorPanel.this.popupMenu.showCallsMenu.doClick(); + } + break; + + case KeyEvent.VK_O: + EditorPanel.this.popupMenu.toggleMappingMenu.doClick(); + break; + + case KeyEvent.VK_R: + EditorPanel.this.popupMenu.renameMenu.doClick(); + break; + + case KeyEvent.VK_D: + EditorPanel.this.popupMenu.editJavadocMenu.doClick(); + break; + + case KeyEvent.VK_F5: + if (EditorPanel.this.classHandle != null) { + EditorPanel.this.classHandle.invalidateMapped(); + } + break; + + case KeyEvent.VK_F: + // prevent navigating on click when quick find activated + break; + + case KeyEvent.VK_ADD: + case KeyEvent.VK_EQUALS: + case KeyEvent.VK_PLUS: + offsetEditorZoom(2); + break; + case KeyEvent.VK_SUBTRACT: + case KeyEvent.VK_MINUS: + offsetEditorZoom(-2); + break; + + default: + EditorPanel.this.shouldNavigateOnClick = true; // CTRL + break; + } + } + } + + @Override + public void keyTyped(KeyEvent event) { + if (!EditorPanel.this.popupMenu.renameMenu.isEnabled()) return; + + if (!event.isControlDown() && !event.isAltDown() && Character.isJavaIdentifierPart(event.getKeyChar())) { + EnigmaProject project = gui.getController().project; + EntryReference, Entry> reference = project.getMapper().deobfuscate(EditorPanel.this.cursorReference); + Entry entry = reference.getNameableEntry(); + + String name = String.valueOf(event.getKeyChar()); + if (entry instanceof ClassEntry && ((ClassEntry) entry).getParent() == null) { + String packageName = ((ClassEntry) entry).getPackageName(); + if (packageName != null) { + name = packageName + "/" + name; + } + } + + gui.startRename(EditorPanel.this, name); + } + } + + @Override + public void keyReleased(KeyEvent event) { + EditorPanel.this.shouldNavigateOnClick = event.isControlDown(); + } + }); + + this.retryButton.addActionListener(_e -> redecompileClass()); + + this.themeChangeListener = (laf, boxHighlightPainters) -> { + if ((this.editorLaf == null || this.editorLaf != laf)) { + this.editor.updateUI(); + this.editor.setBackground(new Color(Config.getInstance().editorBackground)); + if (this.editorLaf != null) { + this.classHandle.invalidateMapped(); + } + + this.editorLaf = laf; + } + this.boxHighlightPainters = boxHighlightPainters; + }; + + this.ui.putClientProperty(EditorPanel.class, this); + } + + @Nullable + public static EditorPanel byUi(Component ui) { + if (ui instanceof JComponent) { + Object prop = ((JComponent) ui).getClientProperty(EditorPanel.class); + if (prop instanceof EditorPanel) { + return (EditorPanel) prop; + } + } + return null; + } + + public void setClassHandle(ClassHandle handle) { + ClassEntry old = null; + if (this.classHandle != null) { + old = this.classHandle.getRef(); + this.classHandle.close(); + } + setClassHandle0(old, handle); + } + + private void setClassHandle0(ClassEntry old, ClassHandle handle) { + this.setDisplayMode(DisplayMode.IN_PROGRESS); + setCursorReference(null); + + handle.addListener(new ClassHandleListener() { + @Override + public void onDeobfRefChanged(ClassHandle h, ClassEntry deobfRef) { + SwingUtilities.invokeLater(() -> { + EditorPanel.this.listeners.forEach(l -> l.onTitleChanged(EditorPanel.this, getFileName())); + }); + } + + @Override + public void onMappedSourceChanged(ClassHandle h, Result res) { + handleDecompilerResult(res); + } + + @Override + public void onInvalidate(ClassHandle h, InvalidationType t) { + SwingUtilities.invokeLater(() -> { + if (t == InvalidationType.FULL) { + EditorPanel.this.setDisplayMode(DisplayMode.IN_PROGRESS); + } + }); + } + + @Override + public void onDeleted(ClassHandle h) { + SwingUtilities.invokeLater(() -> EditorPanel.this.gui.closeEditor(EditorPanel.this)); + } + }); + + handle.getSource().thenAcceptAsync(this::handleDecompilerResult, SwingUtilities::invokeLater); + + this.classHandle = handle; + this.listeners.forEach(l -> l.onClassHandleChanged(this, old, handle)); + } + + public void setup() { + Themes.addListener(this.themeChangeListener); + } + + public void destroy() { + Themes.removeListener(this.themeChangeListener); + this.classHandle.close(); + } + + private void redecompileClass() { + if (this.classHandle != null) { + this.classHandle.invalidate(); + } + } + + private void handleDecompilerResult(Result res) { + SwingUtilities.invokeLater(() -> { + if (res.isOk()) { + this.setSource(res.unwrap()); + } else { + this.displayError(res.unwrapErr()); + } + }); + } + + public void displayError(ClassHandleError t) { + this.setDisplayMode(DisplayMode.ERRORED); + String str; + switch(t.type) { + case DECOMPILE: + str = "editor.decompile_error"; + break; + case REMAP: + str = "editor.remap_error"; + break; + default: + throw new IllegalStateException("unreachable"); + } + this.errorLabel.setText(I18n.translate(str)); + this.errorTextArea.setText(t.getStackTrace()); + this.errorTextArea.setCaretPosition(0); + } + + public void setDisplayMode(DisplayMode mode) { + if (this.mode == mode) return; + this.ui.removeAll(); + switch (mode) { + case INACTIVE: + break; + case IN_PROGRESS: { + // make progress bar start from the left every time + this.decompilingProgressBar.setIndeterminate(false); + this.decompilingProgressBar.setIndeterminate(true); + + this.ui.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.insets = ScaleUtil.getInsets(2, 2, 2, 2); + c.anchor = GridBagConstraints.SOUTH; + this.ui.add(this.decompilingLabel, c); + c.gridy = 1; + c.anchor = GridBagConstraints.NORTH; + this.ui.add(this.decompilingProgressBar, c); + break; + } + case SUCCESS: { + this.ui.setLayout(new GridLayout(1, 1, 0, 0)); + this.ui.add(this.editorScrollPane); + break; + } + case ERRORED: { + this.ui.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = ScaleUtil.getInsets(2, 2, 2, 2); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1.0; + c.anchor = GridBagConstraints.WEST; + this.ui.add(this.errorLabel, c); + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + this.ui.add(new JSeparator(JSeparator.HORIZONTAL), c); + c.gridy = 2; + c.fill = GridBagConstraints.BOTH; + c.weighty = 1.0; + this.ui.add(this.errorScrollPane, c); + c.gridy = 3; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.EAST; + c.weightx = 0.0; + c.weighty = 0.0; + this.ui.add(this.retryButton, c); + break; + } + } + this.ui.validate(); + this.ui.repaint(); + this.mode = mode; + } + + public void offsetEditorZoom(int zoomAmount) { + int newResult = this.fontSize + zoomAmount; + if (newResult > 8 && newResult < 72) { + this.fontSize = newResult; + this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); + } + } + + public void resetEditorZoom() { + this.fontSize = 12; + this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); + } + + public void onCaretMove(int pos, boolean fromClick) { + if (this.controller.project == null) return; + + EntryRemapper mapper = this.controller.project.getMapper(); + Token token = getToken(pos); + + if (this.settingSource) { + EntryReference, Entry> ref = getCursorReference(); + EntryReference, Entry> refAtCursor = getReference(token); + if (this.editor.getDocument().getLength() != 0 && ref != null && !ref.equals(refAtCursor)) { + showReference0(ref); + } + return; + } else { + setCursorReference(getReference(token)); + } + + Entry referenceEntry = this.cursorReference != null ? this.cursorReference.entry : null; + + if (referenceEntry != null && this.shouldNavigateOnClick && fromClick) { + this.shouldNavigateOnClick = false; + Entry navigationEntry = referenceEntry; + if (this.cursorReference.context == null) { + EntryResolver resolver = mapper.getObfResolver(); + navigationEntry = resolver.resolveFirstEntry(referenceEntry, ResolutionStrategy.RESOLVE_ROOT); + } + this.controller.navigateTo(navigationEntry); + } + } + + private void setCursorReference(EntryReference, Entry> ref) { + this.cursorReference = ref; + + Entry referenceEntry = ref == null ? null : ref.entry; + + boolean isClassEntry = referenceEntry instanceof ClassEntry; + boolean isFieldEntry = referenceEntry instanceof FieldEntry; + boolean isMethodEntry = referenceEntry instanceof MethodEntry && !((MethodEntry) referenceEntry).isConstructor(); + boolean isConstructorEntry = referenceEntry instanceof MethodEntry && ((MethodEntry) referenceEntry).isConstructor(); + boolean isRenamable = ref != null && this.controller.project.isRenamable(ref); + + this.popupMenu.renameMenu.setEnabled(isRenamable); + this.popupMenu.editJavadocMenu.setEnabled(isRenamable); + this.popupMenu.showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry); + this.popupMenu.showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry); + this.popupMenu.showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry); + this.popupMenu.showCallsSpecificMenu.setEnabled(isMethodEntry); + this.popupMenu.openEntryMenu.setEnabled(isRenamable && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry)); + this.popupMenu.openPreviousMenu.setEnabled(this.controller.hasPreviousReference()); + this.popupMenu.openNextMenu.setEnabled(this.controller.hasNextReference()); + this.popupMenu.toggleMappingMenu.setEnabled(isRenamable); + + if (referenceEntry != null && referenceEntry.equals(this.controller.project.getMapper().deobfuscate(referenceEntry))) { + this.popupMenu.toggleMappingMenu.setText(I18n.translate("popup_menu.reset_obfuscated")); + } else { + this.popupMenu.toggleMappingMenu.setText(I18n.translate("popup_menu.mark_deobfuscated")); + } + + this.listeners.forEach(l -> l.onCursorReferenceChanged(this, ref)); + } + + public Token getToken(int pos) { + if (this.source == null) { + return null; + } + return this.source.getIndex().getReferenceToken(pos); + } + + @Nullable + public EntryReference, Entry> getReference(Token token) { + if (this.source == null) { + return null; + } + return this.source.getIndex().getReference(token); + } + + public void setSource(DecompiledClassSource source) { + this.setDisplayMode(DisplayMode.SUCCESS); + if (source == null) return; + try { + this.settingSource = true; + this.source = source; + this.editor.getHighlighter().removeAllHighlights(); + this.editor.setText(source.toString()); + setHighlightedTokens(source.getHighlightedTokens()); + } finally { + this.settingSource = false; + } + showReference0(getCursorReference()); + } + + public void setHighlightedTokens(Map> tokens) { + // remove any old highlighters + this.editor.getHighlighter().removeAllHighlights(); + + if (this.boxHighlightPainters != null) { + for (RenamableTokenType type : tokens.keySet()) { + BoxHighlightPainter painter = this.boxHighlightPainters.get(type); + if (painter != null) { + setHighlightedTokens(tokens.get(type), painter); + } + } + } + + this.editor.validate(); + this.editor.repaint(); + } + + private void setHighlightedTokens(Iterable tokens, Highlighter.HighlightPainter painter) { + for (Token token : tokens) { + try { + this.editor.getHighlighter().addHighlight(token.start, token.end, painter); + } catch (BadLocationException ex) { + throw new IllegalArgumentException(ex); + } + } + } + + public EntryReference, Entry> getCursorReference() { + return this.cursorReference; + } + + public void showReference(EntryReference, Entry> reference) { + setCursorReference(reference); + showReference0(reference); + } + + /** + * Navigates to the reference without modifying history. Assumes the class is loaded. + * + * @param reference + */ + private void showReference0(EntryReference, Entry> reference) { + if (this.source == null) return; + if (reference == null) return; + + Collection tokens = this.controller.getTokensForReference(this.source, reference); + if (tokens.isEmpty()) { + // DEBUG + System.err.println(String.format("WARNING: no tokens found for %s in %s", reference, this.classHandle.getRef())); + } else { + this.gui.showTokens(this, tokens); + } + } + + public void navigateToToken(Token token) { + if (token == null) { + throw new IllegalArgumentException("Token cannot be null!"); + } + navigateToToken(token, SelectionHighlightPainter.INSTANCE); + } + + private void navigateToToken(Token token, HighlightPainter highlightPainter) { + // set the caret position to the token + Document document = this.editor.getDocument(); + int clampedPosition = Math.min(Math.max(token.start, 0), document.getLength()); + + this.editor.setCaretPosition(clampedPosition); + this.editor.grabFocus(); + + try { + // make sure the token is visible in the scroll window + Rectangle start = this.editor.modelToView(token.start); + Rectangle end = this.editor.modelToView(token.end); + if (start == null || end == null) { + return; + } + Rectangle show = start.union(end); + show.grow(start.width * 10, start.height * 6); + SwingUtilities.invokeLater(() -> this.editor.scrollRectToVisible(show)); + } catch (BadLocationException ex) { + if (!this.settingSource) { + throw new RuntimeException(ex); + } else { + return; + } + } + + // highlight the token momentarily + Timer timer = new Timer(200, new ActionListener() { + private int counter = 0; + private Object highlight = null; + + @Override + public void actionPerformed(ActionEvent event) { + if (this.counter % 2 == 0) { + try { + this.highlight = EditorPanel.this.editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter); + } catch (BadLocationException ex) { + // don't care + } + } else if (this.highlight != null) { + EditorPanel.this.editor.getHighlighter().removeHighlight(this.highlight); + } + + if (this.counter++ > 6) { + Timer timer = (Timer) event.getSource(); + timer.stop(); + } + } + }); + timer.start(); + } + + public void addListener(EditorActionListener listener) { + this.listeners.add(listener); + } + + public void removeListener(EditorActionListener listener) { + this.listeners.remove(listener); + } + + public JPanel getUi() { + return this.ui; + } + + public JEditorPane getEditor() { + return this.editor; + } + + public DecompiledClassSource getSource() { + return this.source; + } + + public ClassHandle getClassHandle() { + return this.classHandle; + } + + public String getFileName() { + ClassEntry classEntry = this.classHandle.getDeobfRef() != null ? this.classHandle.getDeobfRef() : this.classHandle.getRef(); + return classEntry.getSimpleName(); + } + + private enum DisplayMode { + INACTIVE, + IN_PROGRESS, + SUCCESS, + ERRORED, + } + +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java new file mode 100644 index 0000000..10f8eb5 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java @@ -0,0 +1,255 @@ +package cuchaz.enigma.gui.panels; + +import java.awt.*; +import java.awt.event.ItemEvent; +import java.util.function.Consumer; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import cuchaz.enigma.EnigmaProject; +import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.gui.elements.ConvertingTextField; +import cuchaz.enigma.gui.events.ConvertingTextFieldListener; +import cuchaz.enigma.gui.util.GuiUtil; +import cuchaz.enigma.gui.util.ScaleUtil; +import cuchaz.enigma.network.packet.RenameC2SPacket; +import cuchaz.enigma.translation.mapping.AccessModifier; +import cuchaz.enigma.translation.mapping.EntryMapping; +import cuchaz.enigma.translation.representation.entry.*; +import cuchaz.enigma.utils.I18n; +import cuchaz.enigma.utils.validation.ValidationContext; + +public class IdentifierPanel { + + private final Gui gui; + + private final JPanel ui; + + private Entry entry; + private Entry deobfEntry; + + private ConvertingTextField nameField; + + private final ValidationContext vc = new ValidationContext(); + + public IdentifierPanel(Gui gui) { + this.gui = gui; + + this.ui = new JPanel(); + this.ui.setLayout(new GridBagLayout()); + this.ui.setPreferredSize(ScaleUtil.getDimension(0, 120)); + this.ui.setBorder(BorderFactory.createTitledBorder(I18n.translate("info_panel.identifier"))); + this.ui.setEnabled(false); + } + + public void setReference(Entry entry) { + this.entry = entry; + refreshReference(); + } + + public boolean startRenaming() { + if (this.nameField == null) return false; + + this.nameField.startEditing(); + + return true; + } + + public boolean startRenaming(String text) { + if (this.nameField == null) return false; + + this.nameField.startEditing(); + this.nameField.setEditText(text); + + return true; + } + + private void onModifierChanged(AccessModifier modifier) { + gui.validateImmediateAction(vc -> this.gui.getController().onModifierChanged(vc, entry, modifier)); + } + + public void refreshReference() { + this.deobfEntry = entry == null ? null : gui.getController().project.getMapper().deobfuscate(this.entry); + + this.nameField = null; + + TableHelper th = new TableHelper(this.ui, this.entry, this.gui.getController().project); + th.begin(); + if (this.entry == null) { + this.ui.setEnabled(false); + } else { + this.ui.setEnabled(true); + + if (deobfEntry instanceof ClassEntry) { + ClassEntry ce = (ClassEntry) deobfEntry; + this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.class"), ce.getFullName()); + th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), this::onModifierChanged); + } else if (deobfEntry instanceof FieldEntry) { + FieldEntry fe = (FieldEntry) deobfEntry; + this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.field"), fe.getName()); + th.addStringRow(I18n.translate("info_panel.identifier.class"), fe.getParent().getFullName()); + th.addStringRow(I18n.translate("info_panel.identifier.type_descriptor"), fe.getDesc().toString()); + th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), this::onModifierChanged); + } else if (deobfEntry instanceof MethodEntry) { + MethodEntry me = (MethodEntry) deobfEntry; + if (me.isConstructor()) { + th.addStringRow(I18n.translate("info_panel.identifier.constructor"), me.getParent().getFullName()); + } else { + this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.method"), me.getName()); + th.addStringRow(I18n.translate("info_panel.identifier.class"), me.getParent().getFullName()); + } + th.addStringRow(I18n.translate("info_panel.identifier.method_descriptor"), me.getDesc().toString()); + th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), this::onModifierChanged); + } else if (deobfEntry instanceof LocalVariableEntry) { + LocalVariableEntry lve = (LocalVariableEntry) deobfEntry; + this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.variable"), lve.getName()); + th.addStringRow(I18n.translate("info_panel.identifier.class"), lve.getContainingClass().getFullName()); + th.addStringRow(I18n.translate("info_panel.identifier.method"), lve.getParent().getName()); + th.addStringRow(I18n.translate("info_panel.identifier.index"), Integer.toString(lve.getIndex())); + } else { + throw new IllegalStateException("unreachable"); + } + } + th.end(); + + if (this.nameField != null) { + this.nameField.addListener(new ConvertingTextFieldListener() { + @Override + public void onStartEditing(ConvertingTextField field) { + int i = field.getText().lastIndexOf('/'); + if (i != -1) { + field.selectSubstring(i + 1); + } + } + + @Override + public boolean tryStopEditing(ConvertingTextField field, boolean abort) { + if (abort) return true; + vc.reset(); + vc.setActiveElement(field); + validateRename(field.getText()); + return vc.canProceed(); + } + + @Override + public void onStopEditing(ConvertingTextField field, boolean abort) { + if (abort) return; + vc.reset(); + vc.setActiveElement(field); + doRename(field.getText()); + } + }); + } + + this.ui.validate(); + this.ui.repaint(); + } + + private void validateRename(String newName) { + gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true, true); + } + + private void doRename(String newName) { + gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true); + if (!vc.canProceed()) return; + gui.getController().sendPacket(new RenameC2SPacket(entry, newName, true)); + } + + public JPanel getUi() { + return ui; + } + + private static final class TableHelper { + + private final Container c; + private final Entry e; + private final EnigmaProject project; + private final GridBagConstraints col1; + private final GridBagConstraints col2; + + public TableHelper(Container c, Entry e, EnigmaProject project) { + this.c = c; + this.e = e; + this.project = project; + this.col1 = new GridBagConstraints(); + this.col2 = new GridBagConstraints(); + Insets insets = ScaleUtil.getInsets(2, 2, 2, 2); + this.col1.gridx = 0; + this.col1.gridy = 0; + this.col1.insets = insets; + this.col1.anchor = GridBagConstraints.WEST; + this.col2.gridx = 1; + this.col2.gridy = 0; + this.col2.weightx = 1.0; + this.col2.fill = GridBagConstraints.HORIZONTAL; + this.col2.insets = insets; + this.col2.anchor = GridBagConstraints.WEST; + } + + public void begin() { + c.removeAll(); + c.setLayout(new GridBagLayout()); + } + + public void addRow(Component c1, Component c2) { + c.add(c1, col1); + c.add(c2, col2); + + col1.gridy += 1; + col2.gridy += 1; + } + + public ConvertingTextField addCovertTextField(String c1, String c2) { + ConvertingTextField textField = new ConvertingTextField(c2); + addRow(new JLabel(c1), textField.getUi()); + return textField; + } + + public ConvertingTextField addRenameTextField(String c1, String c2) { + if (project.isRenamable(e)) { + return addCovertTextField(c1, c2); + } else { + addStringRow(c1, c2); + return null; + } + } + + public void addStringRow(String c1, String c2) { + addRow(new JLabel(c1), GuiUtil.unboldLabel(new JLabel(c2))); + } + + public JComboBox addModifierRow(String c1, Consumer changeListener) { + if (!project.isRenamable(e)) + return null; + JComboBox combo = new JComboBox<>(AccessModifier.values()); + EntryMapping mapping = project.getMapper().getDeobfMapping(e); + if (mapping != null) { + combo.setSelectedIndex(mapping.getAccessModifier().ordinal()); + } else { + combo.setSelectedIndex(AccessModifier.UNCHANGED.ordinal()); + } + combo.addItemListener(event -> { + if (event.getStateChange() == ItemEvent.SELECTED) { + AccessModifier modifier = (AccessModifier) event.getItem(); + changeListener.accept(modifier); + } + }); + + addRow(new JLabel(c1), combo); + + return combo; + } + + public void end() { + // Add an empty panel with y-weight=1 so that all the other elements get placed at the top edge + this.col1.weighty = 1.0; + c.add(new JPanel(), col1); + } + + } + +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java new file mode 100644 index 0000000..0ca0583 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java @@ -0,0 +1,40 @@ +package cuchaz.enigma.gui.panels; + +import java.awt.BorderLayout; +import java.util.Comparator; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import cuchaz.enigma.gui.ClassSelector; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.translation.representation.entry.ClassEntry; +import cuchaz.enigma.utils.I18n; + +public class ObfPanel extends JPanel { + + public final ClassSelector obfClasses; + private final Gui gui; + + public ObfPanel(Gui gui) { + this.gui = gui; + + Comparator obfClassComparator = (a, b) -> { + String aname = a.getFullName(); + String bname = b.getFullName(); + if (aname.length() != bname.length()) { + return aname.length() - bname.length(); + } + return aname.compareTo(bname); + }; + + this.obfClasses = new ClassSelector(gui, obfClassComparator, false); + this.obfClasses.setSelectionListener(gui.getController()::navigateTo); + this.obfClasses.setRenameSelectionListener(gui::onPanelRename); + + this.setLayout(new BorderLayout()); + this.add(new JLabel(I18n.translate("info_panel.classes.obfuscated")), BorderLayout.NORTH); + this.add(new JScrollPane(this.obfClasses), BorderLayout.CENTER); + } +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java deleted file mode 100644 index c24226b..0000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java +++ /dev/null @@ -1,26 +0,0 @@ -package cuchaz.enigma.gui.panels; - -import cuchaz.enigma.gui.ClassSelector; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.utils.I18n; - -import javax.swing.*; -import java.awt.*; - -public class PanelDeobf extends JPanel { - - public final ClassSelector deobfClasses; - private final Gui gui; - - public PanelDeobf(Gui gui) { - this.gui = gui; - - this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); - this.deobfClasses.setSelectionListener(gui.getController()::navigateTo); - this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); - - this.setLayout(new BorderLayout()); - this.add(new JLabel(I18n.translate("info_panel.classes.deobfuscated")), BorderLayout.NORTH); - this.add(new JScrollPane(this.deobfClasses), BorderLayout.CENTER); - } -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java deleted file mode 100644 index bf1d5fb..0000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java +++ /dev/null @@ -1,666 +0,0 @@ -package cuchaz.enigma.gui.panels; - -import java.awt.*; -import java.awt.event.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; -import javax.swing.*; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.text.Highlighter; -import javax.swing.text.Highlighter.HighlightPainter; - -import de.sciss.syntaxpane.DefaultSyntaxKit; - -import cuchaz.enigma.EnigmaProject; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.classhandle.ClassHandle; -import cuchaz.enigma.classhandle.ClassHandleError; -import cuchaz.enigma.events.ClassHandleListener; -import cuchaz.enigma.gui.BrowserCaret; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.gui.GuiController; -import cuchaz.enigma.gui.config.Config; -import cuchaz.enigma.gui.config.Themes; -import cuchaz.enigma.gui.elements.PopupMenuBar; -import cuchaz.enigma.gui.events.EditorActionListener; -import cuchaz.enigma.gui.events.ThemeChangeListener; -import cuchaz.enigma.gui.highlight.BoxHighlightPainter; -import cuchaz.enigma.gui.highlight.SelectionHighlightPainter; -import cuchaz.enigma.gui.util.ScaleUtil; -import cuchaz.enigma.source.DecompiledClassSource; -import cuchaz.enigma.source.RenamableTokenType; -import cuchaz.enigma.source.Token; -import cuchaz.enigma.translation.mapping.EntryRemapper; -import cuchaz.enigma.translation.mapping.EntryResolver; -import cuchaz.enigma.translation.mapping.ResolutionStrategy; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.translation.representation.entry.Entry; -import cuchaz.enigma.translation.representation.entry.FieldEntry; -import cuchaz.enigma.translation.representation.entry.MethodEntry; -import cuchaz.enigma.utils.I18n; -import cuchaz.enigma.utils.Result; - -public class PanelEditor { - - private final JPanel ui = new JPanel(); - private final JEditorPane editor = new JEditorPane(); - private final JScrollPane editorScrollPane = new JScrollPane(this.editor); - private final PopupMenuBar popupMenu; - - // progress UI - private final JLabel decompilingLabel = new JLabel(I18n.translate("editor.decompiling"), JLabel.CENTER); - private final JProgressBar decompilingProgressBar = new JProgressBar(0, 100); - - // error display UI - private final JLabel errorLabel = new JLabel(); - private final JTextArea errorTextArea = new JTextArea(); - private final JScrollPane errorScrollPane = new JScrollPane(this.errorTextArea); - private final JButton retryButton = new JButton(I18n.translate("general.retry")); - - private DisplayMode mode = DisplayMode.INACTIVE; - - private final GuiController controller; - private final Gui gui; - - private EntryReference, Entry> cursorReference; - private boolean mouseIsPressed = false; - private boolean shouldNavigateOnClick; - - public Config.LookAndFeel editorLaf; - private int fontSize = 12; - private Map boxHighlightPainters; - - private final List listeners = new ArrayList<>(); - - private final ThemeChangeListener themeChangeListener; - - private ClassHandle classHandle; - private DecompiledClassSource source; - private boolean settingSource; - - public PanelEditor(Gui gui) { - this.gui = gui; - this.controller = gui.getController(); - - this.editor.setEditable(false); - this.editor.setSelectionColor(new Color(31, 46, 90)); - this.editor.setCaret(new BrowserCaret()); - this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); - this.editor.addCaretListener(event -> onCaretMove(event.getDot(), this.mouseIsPressed)); - this.editor.setCaretColor(new Color(Config.getInstance().caretColor)); - this.editor.setContentType("text/enigma-sources"); - this.editor.setBackground(new Color(Config.getInstance().editorBackground)); - DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); - kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker"); - - // init editor popup menu - this.popupMenu = new PopupMenuBar(this, gui); - this.editor.setComponentPopupMenu(this.popupMenu); - - this.decompilingLabel.setFont(ScaleUtil.getFont(this.decompilingLabel.getFont().getFontName(), Font.BOLD, 26)); - this.decompilingProgressBar.setIndeterminate(true); - this.errorTextArea.setEditable(false); - this.errorTextArea.setFont(ScaleUtil.getFont(Font.MONOSPACED, Font.PLAIN, 10)); - - this.boxHighlightPainters = Themes.getBoxHighlightPainters(); - - this.editor.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent mouseEvent) { - PanelEditor.this.mouseIsPressed = true; - } - - @Override - public void mouseReleased(MouseEvent e) { - switch (e.getButton()) { - case MouseEvent.BUTTON3: // Right click - PanelEditor.this.editor.setCaretPosition(PanelEditor.this.editor.viewToModel(e.getPoint())); - break; - - case 4: // Back navigation - gui.getController().openPreviousReference(); - break; - - case 5: // Forward navigation - gui.getController().openNextReference(); - break; - } - PanelEditor.this.mouseIsPressed = false; - } - }); - this.editor.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent event) { - if (event.isControlDown()) { - PanelEditor.this.shouldNavigateOnClick = false; - switch (event.getKeyCode()) { - case KeyEvent.VK_I: - PanelEditor.this.popupMenu.showInheritanceMenu.doClick(); - break; - - case KeyEvent.VK_M: - PanelEditor.this.popupMenu.showImplementationsMenu.doClick(); - break; - - case KeyEvent.VK_N: - PanelEditor.this.popupMenu.openEntryMenu.doClick(); - break; - - case KeyEvent.VK_P: - PanelEditor.this.popupMenu.openPreviousMenu.doClick(); - break; - - case KeyEvent.VK_E: - PanelEditor.this.popupMenu.openNextMenu.doClick(); - break; - - case KeyEvent.VK_C: - if (event.isShiftDown()) { - PanelEditor.this.popupMenu.showCallsSpecificMenu.doClick(); - } else { - PanelEditor.this.popupMenu.showCallsMenu.doClick(); - } - break; - - case KeyEvent.VK_O: - PanelEditor.this.popupMenu.toggleMappingMenu.doClick(); - break; - - case KeyEvent.VK_R: - PanelEditor.this.popupMenu.renameMenu.doClick(); - break; - - case KeyEvent.VK_D: - PanelEditor.this.popupMenu.editJavadocMenu.doClick(); - break; - - case KeyEvent.VK_F5: - if (PanelEditor.this.classHandle != null) { - PanelEditor.this.classHandle.invalidateMapped(); - } - break; - - case KeyEvent.VK_F: - // prevent navigating on click when quick find activated - break; - - case KeyEvent.VK_ADD: - case KeyEvent.VK_EQUALS: - case KeyEvent.VK_PLUS: - offsetEditorZoom(2); - break; - case KeyEvent.VK_SUBTRACT: - case KeyEvent.VK_MINUS: - offsetEditorZoom(-2); - break; - - default: - PanelEditor.this.shouldNavigateOnClick = true; // CTRL - break; - } - } - } - - @Override - public void keyTyped(KeyEvent event) { - if (!PanelEditor.this.popupMenu.renameMenu.isEnabled()) return; - - if (!event.isControlDown() && !event.isAltDown() && Character.isJavaIdentifierPart(event.getKeyChar())) { - EnigmaProject project = gui.getController().project; - EntryReference, Entry> reference = project.getMapper().deobfuscate(PanelEditor.this.cursorReference); - Entry entry = reference.getNameableEntry(); - - String name = String.valueOf(event.getKeyChar()); - if (entry instanceof ClassEntry && ((ClassEntry) entry).getParent() == null) { - String packageName = ((ClassEntry) entry).getPackageName(); - if (packageName != null) { - name = packageName + "/" + name; - } - } - - gui.startRename(PanelEditor.this, name); - } - } - - @Override - public void keyReleased(KeyEvent event) { - PanelEditor.this.shouldNavigateOnClick = event.isControlDown(); - } - }); - - this.retryButton.addActionListener(_e -> redecompileClass()); - - this.themeChangeListener = (laf, boxHighlightPainters) -> { - if ((this.editorLaf == null || this.editorLaf != laf)) { - this.editor.updateUI(); - this.editor.setBackground(new Color(Config.getInstance().editorBackground)); - if (this.editorLaf != null) { - this.classHandle.invalidateMapped(); - } - - this.editorLaf = laf; - } - this.boxHighlightPainters = boxHighlightPainters; - }; - - this.ui.putClientProperty(PanelEditor.class, this); - } - - @Nullable - public static PanelEditor byUi(Component ui) { - if (ui instanceof JComponent) { - Object prop = ((JComponent) ui).getClientProperty(PanelEditor.class); - if (prop instanceof PanelEditor) { - return (PanelEditor) prop; - } - } - return null; - } - - public void setClassHandle(ClassHandle handle) { - ClassEntry old = null; - if (this.classHandle != null) { - old = this.classHandle.getRef(); - this.classHandle.close(); - } - setClassHandle0(old, handle); - } - - private void setClassHandle0(ClassEntry old, ClassHandle handle) { - this.setDisplayMode(DisplayMode.IN_PROGRESS); - setCursorReference(null); - - handle.addListener(new ClassHandleListener() { - @Override - public void onDeobfRefChanged(ClassHandle h, ClassEntry deobfRef) { - SwingUtilities.invokeLater(() -> { - PanelEditor.this.listeners.forEach(l -> l.onTitleChanged(PanelEditor.this, getFileName())); - }); - } - - @Override - public void onMappedSourceChanged(ClassHandle h, Result res) { - handleDecompilerResult(res); - } - - @Override - public void onInvalidate(ClassHandle h, InvalidationType t) { - SwingUtilities.invokeLater(() -> { - if (t == InvalidationType.FULL) { - PanelEditor.this.setDisplayMode(DisplayMode.IN_PROGRESS); - } - }); - } - - @Override - public void onDeleted(ClassHandle h) { - SwingUtilities.invokeLater(() -> PanelEditor.this.gui.closeEditor(PanelEditor.this)); - } - }); - - handle.getSource().thenAcceptAsync(this::handleDecompilerResult, SwingUtilities::invokeLater); - - this.classHandle = handle; - this.listeners.forEach(l -> l.onClassHandleChanged(this, old, handle)); - } - - public void setup() { - Themes.addListener(this.themeChangeListener); - } - - public void destroy() { - Themes.removeListener(this.themeChangeListener); - this.classHandle.close(); - } - - private void redecompileClass() { - if (this.classHandle != null) { - this.classHandle.invalidate(); - } - } - - private void handleDecompilerResult(Result res) { - SwingUtilities.invokeLater(() -> { - if (res.isOk()) { - this.setSource(res.unwrap()); - } else { - this.displayError(res.unwrapErr()); - } - }); - } - - public void displayError(ClassHandleError t) { - this.setDisplayMode(DisplayMode.ERRORED); - String str; - switch(t.type) { - case DECOMPILE: - str = "editor.decompile_error"; - break; - case REMAP: - str = "editor.remap_error"; - break; - default: - throw new IllegalStateException("unreachable"); - } - this.errorLabel.setText(I18n.translate(str)); - this.errorTextArea.setText(t.getStackTrace()); - this.errorTextArea.setCaretPosition(0); - } - - public void setDisplayMode(DisplayMode mode) { - if (this.mode == mode) return; - this.ui.removeAll(); - switch (mode) { - case INACTIVE: - break; - case IN_PROGRESS: { - // make progress bar start from the left every time - this.decompilingProgressBar.setIndeterminate(false); - this.decompilingProgressBar.setIndeterminate(true); - - this.ui.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = 0; - c.insets = ScaleUtil.getInsets(2, 2, 2, 2); - c.anchor = GridBagConstraints.SOUTH; - this.ui.add(this.decompilingLabel, c); - c.gridy = 1; - c.anchor = GridBagConstraints.NORTH; - this.ui.add(this.decompilingProgressBar, c); - break; - } - case SUCCESS: { - this.ui.setLayout(new GridLayout(1, 1, 0, 0)); - this.ui.add(this.editorScrollPane); - break; - } - case ERRORED: { - this.ui.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.insets = ScaleUtil.getInsets(2, 2, 2, 2); - c.gridx = 0; - c.gridy = 0; - c.weightx = 1.0; - c.anchor = GridBagConstraints.WEST; - this.ui.add(this.errorLabel, c); - c.gridy = 1; - c.fill = GridBagConstraints.HORIZONTAL; - this.ui.add(new JSeparator(JSeparator.HORIZONTAL), c); - c.gridy = 2; - c.fill = GridBagConstraints.BOTH; - c.weighty = 1.0; - this.ui.add(this.errorScrollPane, c); - c.gridy = 3; - c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.EAST; - c.weightx = 0.0; - c.weighty = 0.0; - this.ui.add(this.retryButton, c); - break; - } - } - this.ui.validate(); - this.ui.repaint(); - this.mode = mode; - } - - public void offsetEditorZoom(int zoomAmount) { - int newResult = this.fontSize + zoomAmount; - if (newResult > 8 && newResult < 72) { - this.fontSize = newResult; - this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); - } - } - - public void resetEditorZoom() { - this.fontSize = 12; - this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); - } - - public void onCaretMove(int pos, boolean fromClick) { - if (this.controller.project == null) return; - - EntryRemapper mapper = this.controller.project.getMapper(); - Token token = getToken(pos); - - if (this.settingSource) { - EntryReference, Entry> ref = getCursorReference(); - EntryReference, Entry> refAtCursor = getReference(token); - if (this.editor.getDocument().getLength() != 0 && ref != null && !ref.equals(refAtCursor)) { - showReference0(ref); - } - return; - } else { - setCursorReference(getReference(token)); - } - - Entry referenceEntry = this.cursorReference != null ? this.cursorReference.entry : null; - - if (referenceEntry != null && this.shouldNavigateOnClick && fromClick) { - this.shouldNavigateOnClick = false; - Entry navigationEntry = referenceEntry; - if (this.cursorReference.context == null) { - EntryResolver resolver = mapper.getObfResolver(); - navigationEntry = resolver.resolveFirstEntry(referenceEntry, ResolutionStrategy.RESOLVE_ROOT); - } - this.controller.navigateTo(navigationEntry); - } - } - - private void setCursorReference(EntryReference, Entry> ref) { - this.cursorReference = ref; - - Entry referenceEntry = ref == null ? null : ref.entry; - - boolean isClassEntry = referenceEntry instanceof ClassEntry; - boolean isFieldEntry = referenceEntry instanceof FieldEntry; - boolean isMethodEntry = referenceEntry instanceof MethodEntry && !((MethodEntry) referenceEntry).isConstructor(); - boolean isConstructorEntry = referenceEntry instanceof MethodEntry && ((MethodEntry) referenceEntry).isConstructor(); - boolean isRenamable = ref != null && this.controller.project.isRenamable(ref); - - this.popupMenu.renameMenu.setEnabled(isRenamable); - this.popupMenu.editJavadocMenu.setEnabled(isRenamable); - this.popupMenu.showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry); - this.popupMenu.showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry); - this.popupMenu.showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry); - this.popupMenu.showCallsSpecificMenu.setEnabled(isMethodEntry); - this.popupMenu.openEntryMenu.setEnabled(isRenamable && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry)); - this.popupMenu.openPreviousMenu.setEnabled(this.controller.hasPreviousReference()); - this.popupMenu.openNextMenu.setEnabled(this.controller.hasNextReference()); - this.popupMenu.toggleMappingMenu.setEnabled(isRenamable); - - if (referenceEntry != null && referenceEntry.equals(this.controller.project.getMapper().deobfuscate(referenceEntry))) { - this.popupMenu.toggleMappingMenu.setText(I18n.translate("popup_menu.reset_obfuscated")); - } else { - this.popupMenu.toggleMappingMenu.setText(I18n.translate("popup_menu.mark_deobfuscated")); - } - - this.listeners.forEach(l -> l.onCursorReferenceChanged(this, ref)); - } - - public Token getToken(int pos) { - if (this.source == null) { - return null; - } - return this.source.getIndex().getReferenceToken(pos); - } - - @Nullable - public EntryReference, Entry> getReference(Token token) { - if (this.source == null) { - return null; - } - return this.source.getIndex().getReference(token); - } - - public void setSource(DecompiledClassSource source) { - this.setDisplayMode(DisplayMode.SUCCESS); - if (source == null) return; - try { - this.settingSource = true; - this.source = source; - this.editor.getHighlighter().removeAllHighlights(); - this.editor.setText(source.toString()); - setHighlightedTokens(source.getHighlightedTokens()); - } finally { - this.settingSource = false; - } - showReference0(getCursorReference()); - } - - public void setHighlightedTokens(Map> tokens) { - // remove any old highlighters - this.editor.getHighlighter().removeAllHighlights(); - - if (this.boxHighlightPainters != null) { - for (RenamableTokenType type : tokens.keySet()) { - BoxHighlightPainter painter = this.boxHighlightPainters.get(type); - if (painter != null) { - setHighlightedTokens(tokens.get(type), painter); - } - } - } - - this.editor.validate(); - this.editor.repaint(); - } - - private void setHighlightedTokens(Iterable tokens, Highlighter.HighlightPainter painter) { - for (Token token : tokens) { - try { - this.editor.getHighlighter().addHighlight(token.start, token.end, painter); - } catch (BadLocationException ex) { - throw new IllegalArgumentException(ex); - } - } - } - - public EntryReference, Entry> getCursorReference() { - return this.cursorReference; - } - - public void showReference(EntryReference, Entry> reference) { - setCursorReference(reference); - showReference0(reference); - } - - /** - * Navigates to the reference without modifying history. Assumes the class is loaded. - * - * @param reference - */ - private void showReference0(EntryReference, Entry> reference) { - if (this.source == null) return; - if (reference == null) return; - - Collection tokens = this.controller.getTokensForReference(this.source, reference); - if (tokens.isEmpty()) { - // DEBUG - System.err.println(String.format("WARNING: no tokens found for %s in %s", reference, this.classHandle.getRef())); - } else { - this.gui.showTokens(this, tokens); - } - } - - public void navigateToToken(Token token) { - if (token == null) { - throw new IllegalArgumentException("Token cannot be null!"); - } - navigateToToken(token, SelectionHighlightPainter.INSTANCE); - } - - private void navigateToToken(Token token, HighlightPainter highlightPainter) { - // set the caret position to the token - Document document = this.editor.getDocument(); - int clampedPosition = Math.min(Math.max(token.start, 0), document.getLength()); - - this.editor.setCaretPosition(clampedPosition); - this.editor.grabFocus(); - - try { - // make sure the token is visible in the scroll window - Rectangle start = this.editor.modelToView(token.start); - Rectangle end = this.editor.modelToView(token.end); - if (start == null || end == null) { - return; - } - Rectangle show = start.union(end); - show.grow(start.width * 10, start.height * 6); - SwingUtilities.invokeLater(() -> this.editor.scrollRectToVisible(show)); - } catch (BadLocationException ex) { - if (!this.settingSource) { - throw new RuntimeException(ex); - } else { - return; - } - } - - // highlight the token momentarily - Timer timer = new Timer(200, new ActionListener() { - private int counter = 0; - private Object highlight = null; - - @Override - public void actionPerformed(ActionEvent event) { - if (this.counter % 2 == 0) { - try { - this.highlight = PanelEditor.this.editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter); - } catch (BadLocationException ex) { - // don't care - } - } else if (this.highlight != null) { - PanelEditor.this.editor.getHighlighter().removeHighlight(this.highlight); - } - - if (this.counter++ > 6) { - Timer timer = (Timer) event.getSource(); - timer.stop(); - } - } - }); - timer.start(); - } - - public void addListener(EditorActionListener listener) { - this.listeners.add(listener); - } - - public void removeListener(EditorActionListener listener) { - this.listeners.remove(listener); - } - - public JPanel getUi() { - return this.ui; - } - - public JEditorPane getEditor() { - return this.editor; - } - - public DecompiledClassSource getSource() { - return this.source; - } - - public ClassHandle getClassHandle() { - return this.classHandle; - } - - public String getFileName() { - ClassEntry classEntry = this.classHandle.getDeobfRef() != null ? this.classHandle.getDeobfRef() : this.classHandle.getRef(); - return classEntry.getSimpleName(); - } - - private enum DisplayMode { - INACTIVE, - IN_PROGRESS, - SUCCESS, - ERRORED, - } - -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java deleted file mode 100644 index bfba845..0000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java +++ /dev/null @@ -1,255 +0,0 @@ -package cuchaz.enigma.gui.panels; - -import java.awt.*; -import java.awt.event.ItemEvent; -import java.util.function.Consumer; - -import javax.swing.BorderFactory; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JPanel; - -import cuchaz.enigma.EnigmaProject; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.gui.elements.ConvertingTextField; -import cuchaz.enigma.gui.events.ConvertingTextFieldListener; -import cuchaz.enigma.gui.util.GuiUtil; -import cuchaz.enigma.gui.util.ScaleUtil; -import cuchaz.enigma.network.packet.RenameC2SPacket; -import cuchaz.enigma.translation.mapping.AccessModifier; -import cuchaz.enigma.translation.mapping.EntryMapping; -import cuchaz.enigma.translation.representation.entry.*; -import cuchaz.enigma.utils.I18n; -import cuchaz.enigma.utils.validation.ValidationContext; - -public class PanelIdentifier { - - private final Gui gui; - - private final JPanel ui; - - private Entry entry; - private Entry deobfEntry; - - private ConvertingTextField nameField; - - private final ValidationContext vc = new ValidationContext(); - - public PanelIdentifier(Gui gui) { - this.gui = gui; - - this.ui = new JPanel(); - this.ui.setLayout(new GridBagLayout()); - this.ui.setPreferredSize(ScaleUtil.getDimension(0, 120)); - this.ui.setBorder(BorderFactory.createTitledBorder(I18n.translate("info_panel.identifier"))); - this.ui.setEnabled(false); - } - - public void setReference(Entry entry) { - this.entry = entry; - refreshReference(); - } - - public boolean startRenaming() { - if (this.nameField == null) return false; - - this.nameField.startEditing(); - - return true; - } - - public boolean startRenaming(String text) { - if (this.nameField == null) return false; - - this.nameField.startEditing(); - this.nameField.setEditText(text); - - return true; - } - - private void onModifierChanged(AccessModifier modifier) { - gui.validateImmediateAction(vc -> this.gui.getController().onModifierChanged(vc, entry, modifier)); - } - - public void refreshReference() { - this.deobfEntry = entry == null ? null : gui.getController().project.getMapper().deobfuscate(this.entry); - - this.nameField = null; - - TableHelper th = new TableHelper(this.ui, this.entry, this.gui.getController().project); - th.begin(); - if (this.entry == null) { - this.ui.setEnabled(false); - } else { - this.ui.setEnabled(true); - - if (deobfEntry instanceof ClassEntry) { - ClassEntry ce = (ClassEntry) deobfEntry; - this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.class"), ce.getFullName()); - th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), this::onModifierChanged); - } else if (deobfEntry instanceof FieldEntry) { - FieldEntry fe = (FieldEntry) deobfEntry; - this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.field"), fe.getName()); - th.addStringRow(I18n.translate("info_panel.identifier.class"), fe.getParent().getFullName()); - th.addStringRow(I18n.translate("info_panel.identifier.type_descriptor"), fe.getDesc().toString()); - th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), this::onModifierChanged); - } else if (deobfEntry instanceof MethodEntry) { - MethodEntry me = (MethodEntry) deobfEntry; - if (me.isConstructor()) { - th.addStringRow(I18n.translate("info_panel.identifier.constructor"), me.getParent().getFullName()); - } else { - this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.method"), me.getName()); - th.addStringRow(I18n.translate("info_panel.identifier.class"), me.getParent().getFullName()); - } - th.addStringRow(I18n.translate("info_panel.identifier.method_descriptor"), me.getDesc().toString()); - th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), this::onModifierChanged); - } else if (deobfEntry instanceof LocalVariableEntry) { - LocalVariableEntry lve = (LocalVariableEntry) deobfEntry; - this.nameField = th.addRenameTextField(I18n.translate("info_panel.identifier.variable"), lve.getName()); - th.addStringRow(I18n.translate("info_panel.identifier.class"), lve.getContainingClass().getFullName()); - th.addStringRow(I18n.translate("info_panel.identifier.method"), lve.getParent().getName()); - th.addStringRow(I18n.translate("info_panel.identifier.index"), Integer.toString(lve.getIndex())); - } else { - throw new IllegalStateException("unreachable"); - } - } - th.end(); - - if (this.nameField != null) { - this.nameField.addListener(new ConvertingTextFieldListener() { - @Override - public void onStartEditing(ConvertingTextField field) { - int i = field.getText().lastIndexOf('/'); - if (i != -1) { - field.selectSubstring(i + 1); - } - } - - @Override - public boolean tryStopEditing(ConvertingTextField field, boolean abort) { - if (abort) return true; - vc.reset(); - vc.setActiveElement(field); - validateRename(field.getText()); - return vc.canProceed(); - } - - @Override - public void onStopEditing(ConvertingTextField field, boolean abort) { - if (abort) return; - vc.reset(); - vc.setActiveElement(field); - doRename(field.getText()); - } - }); - } - - this.ui.validate(); - this.ui.repaint(); - } - - private void validateRename(String newName) { - gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true, true); - } - - private void doRename(String newName) { - gui.getController().rename(vc, new EntryReference<>(entry, deobfEntry.getName()), newName, true); - if (!vc.canProceed()) return; - gui.getController().sendPacket(new RenameC2SPacket(entry, newName, true)); - } - - public JPanel getUi() { - return ui; - } - - private static final class TableHelper { - - private final Container c; - private final Entry e; - private final EnigmaProject project; - private final GridBagConstraints col1; - private final GridBagConstraints col2; - - public TableHelper(Container c, Entry e, EnigmaProject project) { - this.c = c; - this.e = e; - this.project = project; - this.col1 = new GridBagConstraints(); - this.col2 = new GridBagConstraints(); - Insets insets = ScaleUtil.getInsets(2, 2, 2, 2); - this.col1.gridx = 0; - this.col1.gridy = 0; - this.col1.insets = insets; - this.col1.anchor = GridBagConstraints.WEST; - this.col2.gridx = 1; - this.col2.gridy = 0; - this.col2.weightx = 1.0; - this.col2.fill = GridBagConstraints.HORIZONTAL; - this.col2.insets = insets; - this.col2.anchor = GridBagConstraints.WEST; - } - - public void begin() { - c.removeAll(); - c.setLayout(new GridBagLayout()); - } - - public void addRow(Component c1, Component c2) { - c.add(c1, col1); - c.add(c2, col2); - - col1.gridy += 1; - col2.gridy += 1; - } - - public ConvertingTextField addCovertTextField(String c1, String c2) { - ConvertingTextField textField = new ConvertingTextField(c2); - addRow(new JLabel(c1), textField.getUi()); - return textField; - } - - public ConvertingTextField addRenameTextField(String c1, String c2) { - if (project.isRenamable(e)) { - return addCovertTextField(c1, c2); - } else { - addStringRow(c1, c2); - return null; - } - } - - public void addStringRow(String c1, String c2) { - addRow(new JLabel(c1), GuiUtil.unboldLabel(new JLabel(c2))); - } - - public JComboBox addModifierRow(String c1, Consumer changeListener) { - if (!project.isRenamable(e)) - return null; - JComboBox combo = new JComboBox<>(AccessModifier.values()); - EntryMapping mapping = project.getMapper().getDeobfMapping(e); - if (mapping != null) { - combo.setSelectedIndex(mapping.getAccessModifier().ordinal()); - } else { - combo.setSelectedIndex(AccessModifier.UNCHANGED.ordinal()); - } - combo.addItemListener(event -> { - if (event.getStateChange() == ItemEvent.SELECTED) { - AccessModifier modifier = (AccessModifier) event.getItem(); - changeListener.accept(modifier); - } - }); - - addRow(new JLabel(c1), combo); - - return combo; - } - - public void end() { - // Add an empty panel with y-weight=1 so that all the other elements get placed at the top edge - this.col1.weighty = 1.0; - c.add(new JPanel(), col1); - } - - } - -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java deleted file mode 100644 index dd7f9f9..0000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java +++ /dev/null @@ -1,37 +0,0 @@ -package cuchaz.enigma.gui.panels; - -import cuchaz.enigma.gui.ClassSelector; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.utils.I18n; - -import javax.swing.*; -import java.awt.*; -import java.util.Comparator; - -public class PanelObf extends JPanel { - - public final ClassSelector obfClasses; - private final Gui gui; - - public PanelObf(Gui gui) { - this.gui = gui; - - Comparator obfClassComparator = (a, b) -> { - String aname = a.getFullName(); - String bname = b.getFullName(); - if (aname.length() != bname.length()) { - return aname.length() - bname.length(); - } - return aname.compareTo(bname); - }; - - this.obfClasses = new ClassSelector(gui, obfClassComparator, false); - this.obfClasses.setSelectionListener(gui.getController()::navigateTo); - this.obfClasses.setRenameSelectionListener(gui::onPanelRename); - - this.setLayout(new BorderLayout()); - this.add(new JLabel(I18n.translate("info_panel.classes.obfuscated")), BorderLayout.NORTH); - this.add(new JScrollPane(this.obfClasses), BorderLayout.CENTER); - } -} -- cgit v1.2.3