From 4e2e5aa9757feb72d12639c5567200c1495d8c69 Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 19 Jun 2018 23:12:53 +0300 Subject: [PATCH] gui: fix colors to match system theme, add editor theme selector (#297) --- jadx-gui/src/main/java/jadx/gui/JadxGUI.java | 22 +++-- .../java/jadx/gui/settings/JadxSettings.java | 17 +++- .../jadx/gui/settings/JadxSettingsWindow.java | 22 +++++ .../src/main/java/jadx/gui/ui/CodeArea.java | 89 ++++++++++++++----- .../src/main/java/jadx/gui/ui/CodePanel.java | 8 +- .../java/jadx/gui/ui/CommonSearchDialog.java | 66 ++++++++------ .../main/java/jadx/gui/ui/LineNumbers.java | 28 +++--- .../src/main/java/jadx/gui/ui/LogViewer.java | 37 +++----- .../src/main/java/jadx/gui/ui/MainWindow.java | 32 ++++++- .../src/main/java/jadx/gui/ui/TabbedPane.java | 2 +- .../resources/i18n/Messages_en_US.properties | 1 + 11 files changed, 234 insertions(+), 90 deletions(-) diff --git a/jadx-gui/src/main/java/jadx/gui/JadxGUI.java b/jadx-gui/src/main/java/jadx/gui/JadxGUI.java index 5ccc9c2a9..b9057aa31 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxGUI.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxGUI.java @@ -21,15 +21,27 @@ public class JadxGUI { if (!settings.processArgs(args)) { return; } - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - SwingUtilities.invokeLater(() -> { - MainWindow window = new MainWindow(settings); - window.open(); - }); + if (!tryDefaultLookAndFeel()) { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + SwingUtilities.invokeLater(new MainWindow(settings)::open); } catch (Exception e) { LOG.error("Error: {}", e.getMessage(), e); System.exit(1); } } + + private static boolean tryDefaultLookAndFeel() { + String defLaf = System.getProperty("swing.defaultlaf"); + if (defLaf != null) { + try { + UIManager.setLookAndFeel(defLaf); + return true; + } catch (Exception e) { + LOG.error("Failed to set default laf: {}", defLaf, e); + } + } + return false; + } } diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index ac4ae9376..11f3b2468 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory; import jadx.api.JadxArgs; import jadx.cli.JadxCLIArgs; +import jadx.gui.ui.CodeArea; import static jadx.gui.utils.Utils.FONT_HACK; @@ -23,7 +24,7 @@ public class JadxSettings extends JadxCLIArgs { private static final String USER_HOME = System.getProperty("user.home"); private static final int RECENT_FILES_COUNT = 15; - private static final int CURRENT_SETTINGS_VERSION = 1; + private static final int CURRENT_SETTINGS_VERSION = 2; private static final Font DEFAULT_FONT = FONT_HACK != null ? FONT_HACK : new RSyntaxTextArea().getFont(); @@ -36,6 +37,7 @@ public class JadxSettings extends JadxCLIArgs { private boolean checkForUpdates = false; private List recentFiles = new ArrayList<>(); private String fontStr = ""; + private String editorThemePath = ""; private boolean autoStartJobs = false; private int settingsVersion = 0; @@ -210,6 +212,14 @@ public class JadxSettings extends JadxCLIArgs { this.fontStr = font.getFontName() + addStyleName(font.getStyle()) + "-" + font.getSize(); } + public String getEditorThemePath() { + return editorThemePath; + } + + public void setEditorThemePath(String editorThemePath) { + this.editorThemePath = editorThemePath; + } + private static String addStyleName(int style) { switch (style) { case Font.BOLD: @@ -233,7 +243,10 @@ public class JadxSettings extends JadxCLIArgs { setReplaceConsts(true); setSkipResources(false); setAutoStartJobs(false); -// fromVersion++; + fromVersion++; + } + if (fromVersion == 1) { + setEditorThemePath(CodeArea.getAllThemes()[0].getPath()); } settingsVersion = CURRENT_SETTINGS_VERSION; sync(); diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java index 398cfcfc2..e489f877d 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java @@ -12,13 +12,17 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Arrays; import java.util.Collection; +import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import say.swing.JFontChooser; +import jadx.gui.ui.CodeArea; +import jadx.gui.ui.CodeArea.EditorTheme; import jadx.gui.ui.MainWindow; import jadx.gui.utils.NLS; + import static jadx.gui.utils.Utils.FONT_HACK; @@ -196,12 +200,30 @@ public class JadxSettingsWindow extends JDialog { LOG.info("Selected Font : {}", font); settings.setFont(font); mainWindow.updateFont(font); + mainWindow.loadSettings(); } } }); + EditorTheme[] editorThemes = CodeArea.getAllThemes(); + final JComboBox themesCbx = new JComboBox<>(editorThemes); + for (EditorTheme theme: editorThemes) { + if (theme.getPath().equals(settings.getEditorThemePath())) { + themesCbx.setSelectedItem(theme); + break; + } + } + themesCbx.addActionListener(e -> { + int i = themesCbx.getSelectedIndex(); + EditorTheme editorTheme = editorThemes[i]; + settings.setEditorThemePath(editorTheme.getPath()); + mainWindow.setEditorTheme(editorTheme.getPath()); + mainWindow.loadSettings(); + }); + SettingsGroup other = new SettingsGroup(NLS.str("preferences.editor")); other.addRow(NLS.str("preferences.font"), fontBtn); + other.addRow(NLS.str("preferences.theme"), themesCbx); return other; } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java b/jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java index 5264f6d77..4b56af41d 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/CodeArea.java @@ -16,7 +16,6 @@ import java.awt.event.MouseEvent; import org.fife.ui.rsyntaxtextarea.LinkGenerator; import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; -import org.fife.ui.rsyntaxtextarea.SyntaxScheme; import org.fife.ui.rsyntaxtextarea.Token; import org.fife.ui.rsyntaxtextarea.TokenTypes; import org.fife.ui.rtextarea.SearchContext; @@ -32,14 +31,11 @@ import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JNode; import jadx.gui.utils.Position; -class CodeArea extends RSyntaxTextArea { +public final class CodeArea extends RSyntaxTextArea { private static final Logger LOG = LoggerFactory.getLogger(CodeArea.class); private static final long serialVersionUID = 6312736869579635796L; - public static final Color CODE_BACKGROUND = new Color(0xFAFAFA); - public static final Color JUMP_TOKEN_FGD = new Color(0x491BA1); - private final CodePanel contentPanel; private final JNode node; @@ -48,10 +44,9 @@ class CodeArea extends RSyntaxTextArea { this.node = panel.getNode(); setMarkOccurrences(true); - setBackground(CODE_BACKGROUND); - setAntiAliasingEnabled(true); setEditable(false); loadSettings(); + Caret caret = getCaret(); if (caret instanceof DefaultCaret) { ((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); @@ -59,18 +54,13 @@ class CodeArea extends RSyntaxTextArea { caret.setVisible(true); setSyntaxEditingStyle(node.getSyntaxName()); - if (node instanceof JClass) { - SyntaxScheme scheme = getSyntaxScheme(); - scheme.getStyle(Token.FUNCTION).foreground = Color.BLACK; - setHyperlinksEnabled(true); CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator((JClass) node); setLinkGenerator(codeLinkProcessor); addHyperlinkListener(codeLinkProcessor); addMenuItems(this, (JClass) node); } - registerWordHighlighter(); setText(node.getContent()); } @@ -113,8 +103,21 @@ class CodeArea extends RSyntaxTextArea { } public void loadSettings() { - JadxSettings settings = contentPanel.getTabbedPane().getMainWindow().getSettings(); - setFont(settings.getFont()); + loadCommonSettings(contentPanel.getTabbedPane().getMainWindow(), this); + } + + public static void loadCommonSettings(MainWindow mainWindow, RSyntaxTextArea area) { + area.setAntiAliasingEnabled(true); + mainWindow.getEditorTheme().apply(area); + + JadxSettings settings = mainWindow.getSettings(); + area.setFont(settings.getFont()); + } + + public static RSyntaxTextArea getDefaultArea(MainWindow mainWindow) { + RSyntaxTextArea area = new RSyntaxTextArea(); + loadCommonSettings(mainWindow, area); + return area; } private boolean isJumpToken(Token token) { @@ -129,6 +132,16 @@ class CodeArea extends RSyntaxTextArea { if (node instanceof JClass) { Position pos = getDefPosition((JClass) node, this, token.getOffset()); if (pos != null) { + // don't underline definition place + try { + int defLine = pos.getLine(); + int lineOfOffset = getLineOfOffset(token.getOffset()) + 1; + if (defLine == lineOfOffset) { + return false; + } + } catch (BadLocationException e) { + return false; + } return true; } } @@ -136,13 +149,13 @@ class CodeArea extends RSyntaxTextArea { return false; } - @Override - public Color getForegroundForToken(Token t) { - if (isJumpToken(t)) { - return JUMP_TOKEN_FGD; - } - return super.getForegroundForToken(t); - } +// @Override +// public Color getForegroundForToken(Token t) { +// if (isJumpToken(t)) { +// return getHyperlinkForeground(); +// } +// return super.getForegroundForToken(t); +// } static Position getDefPosition(JClass jCls, RSyntaxTextArea textArea, int offset) { JavaNode node = getJavaNodeAtOffset(jCls, textArea, offset); @@ -311,4 +324,38 @@ class CodeArea extends RSyntaxTextArea { } } } + + public static final class EditorTheme { + private final String name; + private final String path; + + public EditorTheme(String name, String path) { + this.name = name; + this.path = path; + } + + public String getName() { + return name; + } + + public String getPath() { + return path; + } + + @Override + public String toString() { + return name; + } + } + + public static EditorTheme[] getAllThemes() { + return new EditorTheme[]{ + new EditorTheme("default", "/org/fife/ui/rsyntaxtextarea/themes/default.xml"), + new EditorTheme("eclipse", "/org/fife/ui/rsyntaxtextarea/themes/eclipse.xml"), + new EditorTheme("idea", "/org/fife/ui/rsyntaxtextarea/themes/idea.xml"), + new EditorTheme("vs", "/org/fife/ui/rsyntaxtextarea/themes/vs.xml"), + new EditorTheme("dark", "/org/fife/ui/rsyntaxtextarea/themes/dark.xml"), + new EditorTheme("monokai", "/org/fife/ui/rsyntaxtextarea/themes/monokai.xml") + }; + } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java index ac7545333..7594a8aa7 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/CodePanel.java @@ -24,7 +24,7 @@ class CodePanel extends ContentPanel { searchBar = new SearchBar(codeArea); scrollPane = new JScrollPane(codeArea); - scrollPane.setRowHeaderView(new LineNumbers(codeArea)); + initLineNumbers(); setLayout(new BorderLayout()); add(searchBar, BorderLayout.NORTH); @@ -34,6 +34,10 @@ class CodePanel extends ContentPanel { Utils.addKeyBinding(codeArea, key, "SearchAction", new SearchAction()); } + private void initLineNumbers() { + scrollPane.setRowHeaderView(new LineNumbers(codeArea)); + } + private class SearchAction extends AbstractAction { private static final long serialVersionUID = 8650568214755387093L; @@ -46,6 +50,8 @@ class CodePanel extends ContentPanel { @Override public void loadSettings() { codeArea.loadSettings(); + initLineNumbers(); + updateUI(); } @Override diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java index a7a5e97ce..71ce8757d 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java @@ -23,6 +23,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rtextarea.SearchContext; import org.fife.ui.rtextarea.SearchEngine; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -152,7 +153,7 @@ public abstract class CommonSearchDialog extends JDialog { resultsTable.setShowHorizontalLines(false); resultsTable.setDragEnabled(false); resultsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - resultsTable.setBackground(CodeArea.CODE_BACKGROUND); +// resultsTable.setBackground(CodeArea.CODE_BACKGROUND); resultsTable.setColumnSelectionAllowed(false); resultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); resultsTable.setAutoscrolls(false); @@ -259,6 +260,7 @@ public abstract class CommonSearchDialog extends JDialog { if (!model.isAddDescColumn()) { firstColMaxWidth = width; } + Component nodeComp = null; Component codeComp = null; for (int col = 0; col < columnCount; col++) { int colWidth = 50; @@ -268,6 +270,9 @@ public abstract class CommonSearchDialog extends JDialog { continue; } colWidth = Math.max(comp.getPreferredSize().width, colWidth); + if (nodeComp == null && col == 0) { + nodeComp = comp; + } if (codeComp == null && col == 1) { codeComp = comp; } @@ -281,10 +286,16 @@ public abstract class CommonSearchDialog extends JDialog { TableColumn column = columnModel.getColumn(col); column.setPreferredWidth(colWidth); } - if (codeComp != null) { - setRowHeight(Math.max(20, codeComp.getPreferredSize().height + 4)); - } +// setRowHeight(Math.max(nodeComp.getPreferredSize().height, codeComp.getPreferredSize().height + 4)); updateUI(); + setRowHeight(Math.max(getHeight(nodeComp), getHeight(codeComp) + 4)); + } + + private int getHeight(@Nullable Component nodeComp) { + if (nodeComp != null) { + return Math.max(nodeComp.getHeight(), nodeComp.getPreferredSize().height); + } + return 0; } } @@ -381,19 +392,15 @@ public abstract class CommonSearchDialog extends JDialog { } protected class ResultsTableCellRenderer implements TableCellRenderer { - private final Color selectedBackground; - private final Color selectedForeground; - private final Color foreground; - private final JLabel emptyLabel = new JLabel(); - + private final Color codeSelectedColor; + private final Color codeBackground; private Map componentCache = new HashMap<>(); public ResultsTableCellRenderer() { - UIDefaults defaults = UIManager.getDefaults(); - foreground = defaults.getColor("List.foreground"); - selectedBackground = defaults.getColor("List.selectionBackground"); - selectedForeground = defaults.getColor("List.selectionForeground"); + RSyntaxTextArea area = CodeArea.getDefaultArea(mainWindow); + this.codeSelectedColor = area.getSelectionColor(); + this.codeBackground = area.getBackground(); } @Override @@ -403,29 +410,38 @@ public abstract class CommonSearchDialog extends JDialog { Component comp = componentCache.get(id); if (comp == null) { if (obj instanceof JNode) { - comp = makeCell((JNode) obj, column); + comp = makeCell(table, (JNode) obj, column); componentCache.put(id, comp); } else { comp = emptyLabel; } } - updateSelection(comp, isSelected); + updateSelection(table, comp, isSelected); return comp; } - private void updateSelection(Component comp, boolean isSelected) { - if (isSelected) { - comp.setBackground(selectedBackground); - comp.setForeground(selectedForeground); + private void updateSelection(JTable table, Component comp, boolean isSelected) { + if (comp instanceof RSyntaxTextArea) { + if (isSelected) { + comp.setBackground(codeSelectedColor); + } else { + comp.setBackground(codeBackground); + } } else { - comp.setBackground(CodeArea.CODE_BACKGROUND); - comp.setForeground(foreground); + if (isSelected) { + comp.setBackground(table.getSelectionBackground()); + comp.setForeground(table.getSelectionForeground()); + } else { + comp.setBackground(table.getBackground()); + comp.setForeground(table.getForeground()); + } } } - private Component makeCell(JNode node, int column) { + private Component makeCell(JTable table, JNode node, int column) { if (column == 0) { JLabel label = new JLabel(node.makeLongString() + " ", node.getIcon(), SwingConstants.LEFT); + label.setFont(table.getFont()); label.setOpaque(true); label.setToolTipText(label.getText()); return label; @@ -433,13 +449,13 @@ public abstract class CommonSearchDialog extends JDialog { if (!node.hasDescString()) { return emptyLabel; } - RSyntaxTextArea textArea = new RSyntaxTextArea(); - textArea.setFont(codeFont); + RSyntaxTextArea textArea = CodeArea.getDefaultArea(mainWindow); + textArea.setLayout(new GridLayout(1, 1)); textArea.setEditable(false); textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); textArea.setText(" " + node.makeDescString()); textArea.setRows(1); - textArea.setColumns(textArea.getText().length()); + textArea.setColumns(textArea.getText().length() + 1); if (highlightText != null) { SearchContext searchContext = new SearchContext(highlightText); searchContext.setMatchCase(!highlightTextCaseInsensitive); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java b/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java index b2dd51601..ab9566568 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/LineNumbers.java @@ -18,15 +18,13 @@ import java.awt.event.MouseEvent; import java.util.HashMap; import java.util.Map; +import org.fife.ui.rsyntaxtextarea.SyntaxScheme; +import org.fife.ui.rsyntaxtextarea.Token; + public class LineNumbers extends JPanel implements CaretListener { private static final long serialVersionUID = -4978268673635308190L; - private static final Border OUTER = new MatteBorder(0, 0, 0, 1, Color.LIGHT_GRAY); - private static final int NUM_HEIGHT = Integer.MAX_VALUE - 1000000; - private static final Color NUM_FOREGROUND = Color.GRAY; - private static final Color NUM_BACKGROUND = CodeArea.CODE_BACKGROUND; - private static final Color CURRENT_LINE_FOREGROUND = new Color(227, 0, 0); private CodeArea codeArea; private boolean useSourceLines = true; @@ -35,11 +33,19 @@ public class LineNumbers extends JPanel implements CaretListener { private int lastLine; private Map fonts; + private transient final Color numberColor; + private transient final Color currentColor; + private transient final Border border; + public LineNumbers(CodeArea component) { this.codeArea = component; setFont(component.getFont()); - setBackground(NUM_BACKGROUND); - setForeground(NUM_FOREGROUND); + SyntaxScheme syntaxScheme = codeArea.getSyntaxScheme(); + numberColor = syntaxScheme.getStyle(Token.LITERAL_NUMBER_DECIMAL_INT).foreground; + currentColor = syntaxScheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).foreground; + border = new MatteBorder(0, 0, 0, 1, syntaxScheme.getStyle(Token.COMMENT_MULTILINE).foreground); + setBackground(codeArea.getBackground()); + setForeground(numberColor); setBorderGap(5); setPreferredWidth(); @@ -58,7 +64,7 @@ public class LineNumbers extends JPanel implements CaretListener { public void setBorderGap(int borderGap) { Border inner = new EmptyBorder(0, borderGap, 0, borderGap); - setBorder(new CompoundBorder(OUTER, inner)); + setBorder(new CompoundBorder(border, inner)); lastDigits = 0; } @@ -85,6 +91,8 @@ public class LineNumbers extends JPanel implements CaretListener { @Override public void paintComponent(Graphics g) { super.paintComponent(g); + g.setFont(codeArea.getFont()); + FontMetrics fontMetrics = codeArea.getFontMetrics(codeArea.getFont()); Insets insets = getInsets(); int availableWidth = getSize().width - insets.left - insets.right; @@ -95,9 +103,9 @@ public class LineNumbers extends JPanel implements CaretListener { while (rowStartOffset <= endOffset) { try { if (isCurrentLine(rowStartOffset)) { - g.setColor(CURRENT_LINE_FOREGROUND); + g.setColor(currentColor); } else { - g.setColor(NUM_FOREGROUND); + g.setColor(numberColor); } String lineNumber = getTextLineNumber(rowStartOffset); int stringWidth = fontMetrics.stringWidth(lineNumber); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java b/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java index 09e5f0576..fd136b01d 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java @@ -2,8 +2,6 @@ package jadx.gui.ui; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import ch.qos.logback.classic.Level; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; @@ -21,28 +19,25 @@ class LogViewer extends JDialog { private final transient JadxSettings settings; private transient RSyntaxTextArea textPane; - public LogViewer(JadxSettings settings) { - this.settings = settings; - initUI(); + public LogViewer(MainWindow mainWindow) { + this.settings = mainWindow.getSettings(); + initUI(mainWindow); registerLogListener(); settings.loadWindowPos(this); } - public final void initUI() { - textPane = new RSyntaxTextArea(); + public final void initUI(MainWindow mainWindow) { + textPane = CodeArea.getDefaultArea(mainWindow); textPane.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); JPanel controlPane = new JPanel(); controlPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); final JComboBox cb = new JComboBox<>(LEVEL_ITEMS); cb.setSelectedItem(level); - cb.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - int i = cb.getSelectedIndex(); - level = LEVEL_ITEMS[i]; - registerLogListener(); - } + cb.addActionListener(e -> { + int i = cb.getSelectedIndex(); + level = LEVEL_ITEMS[i]; + registerLogListener(); }); JLabel levelLabel = new JLabel(NLS.str("log.level")); levelLabel.setLabelFor(cb); @@ -52,11 +47,7 @@ class LogViewer extends JDialog { JScrollPane scrollPane = new JScrollPane(textPane); JButton close = new JButton(NLS.str("tabs.close")); - close.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - close(); - } - }); + close.addActionListener(event -> close()); close.setAlignmentX(0.5f); Container contentPane = getContentPane(); @@ -84,11 +75,9 @@ class LogViewer extends JDialog { @Override public void onAppend(final String logStr) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - textPane.append(logStr); - textPane.updateUI(); - } + SwingUtilities.invokeLater(() -> { + textPane.append(logStr); + textPane.updateUI(); }); } }); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 24303881b..5bccfc82f 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -23,10 +23,12 @@ import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; +import java.io.FileInputStream; import java.util.Arrays; import java.util.Timer; import java.util.TimerTask; +import org.fife.ui.rsyntaxtextarea.Theme; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -98,6 +100,7 @@ public class MainWindow extends JFrame { private transient Link updateLink; private transient ProgressPanel progressPane; private transient BackgroundWorker backgroundWorker; + private transient Theme editorTheme; public MainWindow(JadxSettings settings) { this.wrapper = new JadxWrapper(settings); @@ -107,9 +110,16 @@ public class MainWindow extends JFrame { resetCache(); initUI(); initMenuAndToolbar(); + applySettings(); checkForUpdate(); } + private void applySettings() { + setFont(settings.getFont()); + setEditorTheme(settings.getEditorThemePath()); + loadSettings(); + } + public void open() { pack(); setLocationAndPosition(); @@ -419,7 +429,7 @@ public class MainWindow extends JFrame { Action logAction = new AbstractAction(NLS.str("menu.log"), ICON_LOG) { @Override public void actionPerformed(ActionEvent e) { - new LogViewer(settings).setVisible(true); + new LogViewer(MainWindow.this).setVisible(true); } }; logAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.log")); @@ -613,6 +623,26 @@ public class MainWindow extends JFrame { public void updateFont(Font font) { setFont(font); + } + + public void setEditorTheme(String editorThemePath) { + try { + editorTheme = Theme.load(getClass().getResourceAsStream(editorThemePath)); + } catch (Exception e) { + LOG.error("Can't load editor theme from classpath: {}", editorThemePath); + try { + editorTheme = Theme.load(new FileInputStream(editorThemePath)); + } catch (Exception e2) { + LOG.error("Can't load editor theme from file: {}", editorThemePath); + } + } + } + + public Theme getEditorTheme() { + return editorTheme; + } + + public void loadSettings() { tabbedPane.loadSettings(); } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java index b582bf6e5..d9ccaa3ac 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java @@ -41,7 +41,7 @@ class TabbedPane extends JTabbedPane { private transient JumpManager jumps = new JumpManager(); TabbedPane(MainWindow window) { - mainWindow = window; + this.mainWindow = window; setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 69e66989b..911501986 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -75,6 +75,7 @@ preferences.threads=Processing threads count preferences.cfg=Generate methods CFG graphs (in 'dot' format) preferences.raw_cfg=Generate RAW CFG graphs preferences.font=Editor font +preferences.theme=Editor theme preferences.start_jobs=Auto start background decompilation preferences.select_font=Select preferences.deobfuscation_on=Enable deobfuscation