gui: fix colors to match system theme, add editor theme selector (#297)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String> 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();
|
||||
|
||||
@@ -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<EditorTheme> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Integer, Component> 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);
|
||||
|
||||
@@ -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<String, FontMetrics> 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);
|
||||
|
||||
@@ -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<Level> 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();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user