feat(gui): use FlatLaf for themes support
This commit is contained in:
@@ -66,10 +66,14 @@ public class LogHelper {
|
||||
return logLevelValue;
|
||||
}
|
||||
|
||||
private static void setLevelForClass(Class<?> cls, Level level) {
|
||||
public static void setLevelForClass(Class<?> cls, Level level) {
|
||||
((Logger) LoggerFactory.getLogger(cls)).setLevel(level);
|
||||
}
|
||||
|
||||
public static void setLevelForPackage(String pkgName, Level level) {
|
||||
((Logger) LoggerFactory.getLogger(pkgName)).setLevel(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to detect if user provide custom logback config via -Dlogback.configurationFile=
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,10 @@ dependencies {
|
||||
implementation files('libs/jfontchooser-1.0.5.jar')
|
||||
implementation 'hu.kazocsaba:image-viewer:1.2.3'
|
||||
|
||||
implementation 'com.formdev:flatlaf:1.4'
|
||||
implementation 'com.formdev:flatlaf-intellij-themes:1.4'
|
||||
implementation 'org.reflections:reflections:0.9.12'
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
implementation 'org.apache.commons:commons-text:1.9'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jadx.gui;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -10,6 +9,7 @@ import jadx.cli.LogHelper;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.settings.JadxSettingsAdapter;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.LafManager;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.SystemInfo;
|
||||
import jadx.gui.utils.logs.LogCollector;
|
||||
@@ -20,17 +20,15 @@ public class JadxGUI {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
LogCollector.register();
|
||||
final JadxSettings settings = JadxSettingsAdapter.load();
|
||||
JadxSettings settings = JadxSettingsAdapter.load();
|
||||
settings.setLogLevel(LogHelper.LogLevelEnum.INFO);
|
||||
// overwrite loaded settings by command line arguments
|
||||
if (!settings.overrideProvided(args)) {
|
||||
return;
|
||||
}
|
||||
if (!tryDefaultLookAndFeel()) {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
}
|
||||
NLS.setLocale(settings.getLangLocale());
|
||||
printSystemInfo();
|
||||
LafManager.init(settings);
|
||||
NLS.setLocale(settings.getLangLocale());
|
||||
|
||||
SwingUtilities.invokeLater(new MainWindow(settings)::init);
|
||||
} catch (Exception e) {
|
||||
@@ -39,19 +37,6 @@ public class JadxGUI {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static void printSystemInfo() {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Starting jadx-gui. Version: '{}'. JVM: {} {}. OS: {} {}",
|
||||
|
||||
@@ -33,6 +33,7 @@ import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.codearea.EditorTheme;
|
||||
import jadx.gui.utils.FontUtils;
|
||||
import jadx.gui.utils.LafManager;
|
||||
import jadx.gui.utils.LangLocale;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
@@ -60,6 +61,7 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
private String fontStr = "";
|
||||
private String smaliFontStr = "";
|
||||
private String editorThemePath = "";
|
||||
private String lafTheme = LafManager.SYSTEM_THEME_NAME;
|
||||
private LangLocale langLocale = NLS.defaultLocale();
|
||||
private boolean autoStartJobs = false;
|
||||
protected String excludedPackages = "";
|
||||
@@ -431,6 +433,14 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
this.editorThemePath = editorThemePath;
|
||||
}
|
||||
|
||||
public String getLafTheme() {
|
||||
return lafTheme;
|
||||
}
|
||||
|
||||
public void setLafTheme(String lafTheme) {
|
||||
this.lafTheme = lafTheme;
|
||||
}
|
||||
|
||||
public int getMainWindowExtendedState() {
|
||||
return mainWindowExtendedState;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,50 @@
|
||||
package jadx.gui.settings;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.WindowConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
@@ -27,6 +62,7 @@ import jadx.api.JadxArgs;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.codearea.EditorTheme;
|
||||
import jadx.gui.utils.FontUtils;
|
||||
import jadx.gui.utils.LafManager;
|
||||
import jadx.gui.utils.LangLocale;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
@@ -75,7 +111,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
leftPanel.add(makeDeobfuscationGroup());
|
||||
leftPanel.add(makeRenameGroup());
|
||||
leftPanel.add(makeProjectGroup());
|
||||
leftPanel.add(makeEditorGroup());
|
||||
leftPanel.add(makeAppearanceGroup());
|
||||
leftPanel.add(makeOtherGroup());
|
||||
leftPanel.add(makeSearchResGroup());
|
||||
|
||||
@@ -289,7 +325,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
return group;
|
||||
}
|
||||
|
||||
private SettingsGroup makeEditorGroup() {
|
||||
private SettingsGroup makeAppearanceGroup() {
|
||||
JButton fontBtn = new JButton(NLS.str("preferences.select_font"));
|
||||
JButton smaliFontBtn = new JButton(NLS.str("preferences.select_smali_font"));
|
||||
|
||||
@@ -308,9 +344,17 @@ public class JadxSettingsWindow extends JDialog {
|
||||
mainWindow.loadSettings();
|
||||
});
|
||||
|
||||
SettingsGroup group = new SettingsGroup(NLS.str("preferences.editor"));
|
||||
JLabel fontLabel = group.addRow(getFontLabelStr(), fontBtn);
|
||||
JComboBox<String> lafCbx = new JComboBox<>(LafManager.getThemes());
|
||||
lafCbx.setSelectedItem(settings.getLafTheme());
|
||||
lafCbx.addActionListener(e -> {
|
||||
settings.setLafTheme((String) lafCbx.getSelectedItem());
|
||||
mainWindow.loadSettings();
|
||||
});
|
||||
|
||||
SettingsGroup group = new SettingsGroup(NLS.str("preferences.appearance"));
|
||||
group.addRow(NLS.str("preferences.laf_theme"), lafCbx);
|
||||
group.addRow(NLS.str("preferences.theme"), themesCbx);
|
||||
JLabel fontLabel = group.addRow(getFontLabelStr(), fontBtn);
|
||||
JLabel smaliFontLabel = group.addRow(getSmaliFontLabelStr(), smaliFontBtn);
|
||||
|
||||
fontBtn.addMouseListener(new MouseAdapter() {
|
||||
|
||||
@@ -115,6 +115,7 @@ import jadx.gui.utils.CacheObject;
|
||||
import jadx.gui.utils.CodeUsageInfo;
|
||||
import jadx.gui.utils.FontUtils;
|
||||
import jadx.gui.utils.JumpPosition;
|
||||
import jadx.gui.utils.LafManager;
|
||||
import jadx.gui.utils.Link;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.SystemInfo;
|
||||
@@ -1255,6 +1256,8 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
|
||||
public void loadSettings() {
|
||||
LafManager.updateLaf(settings);
|
||||
|
||||
Font font = settings.getFont();
|
||||
Font largerFont = font.deriveFont(font.getSize() + 2.f);
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package jadx.gui.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import jadx.cli.LogHelper;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
|
||||
public class LafManager {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LafManager.class);
|
||||
|
||||
public static final String SYSTEM_THEME_NAME = "default";
|
||||
private static final Map<String, String> THEMES_MAP = initThemesMap();
|
||||
|
||||
public static void init(JadxSettings settings) {
|
||||
if (setupLaf(getThemeClass(settings))) {
|
||||
return;
|
||||
}
|
||||
setupLaf(SYSTEM_THEME_NAME);
|
||||
settings.setLafTheme(SYSTEM_THEME_NAME);
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
public static void updateLaf(JadxSettings settings) {
|
||||
if (setupLaf(getThemeClass(settings))) {
|
||||
FlatLaf.updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getThemes() {
|
||||
return THEMES_MAP.keySet().toArray(new String[0]);
|
||||
}
|
||||
|
||||
private static String getThemeClass(JadxSettings settings) {
|
||||
return THEMES_MAP.get(settings.getLafTheme());
|
||||
}
|
||||
|
||||
private static boolean setupLaf(String themeClass) {
|
||||
if (SYSTEM_THEME_NAME.equals(themeClass)) {
|
||||
return applyLaf(UIManager.getSystemLookAndFeelClassName());
|
||||
}
|
||||
if (themeClass != null && !themeClass.isEmpty()) {
|
||||
return applyLaf(themeClass);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Map<String, String> initThemesMap() {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
map.put(SYSTEM_THEME_NAME, SYSTEM_THEME_NAME);
|
||||
for (FlatLaf flatLafTheme : collectFlatLafThemes()) {
|
||||
map.put(flatLafTheme.getName(), flatLafTheme.getClass().getName());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static List<FlatLaf> collectFlatLafThemes() {
|
||||
LogHelper.setLevelForPackage("org.reflections", Level.WARN);
|
||||
Reflections reflections = new Reflections("com.formdev.flatlaf");
|
||||
Set<Class<? extends FlatLaf>> lafClasses = reflections.getSubTypesOf(FlatLaf.class);
|
||||
|
||||
List<FlatLaf> themes = new ArrayList<>(lafClasses.size());
|
||||
for (Class<? extends FlatLaf> lafClass : lafClasses) {
|
||||
try {
|
||||
themes.add(lafClass.getDeclaredConstructor().newInstance());
|
||||
} catch (Exception e) {
|
||||
// some classes not themes, ignore them
|
||||
LOG.trace("Failed make instance for class: {}", lafClass.getName(), e);
|
||||
}
|
||||
}
|
||||
themes.sort(Comparator.comparing(LookAndFeel::getName));
|
||||
return themes;
|
||||
}
|
||||
|
||||
private static boolean applyLaf(String theme) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(theme);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to set laf to {}", theme, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ about_dialog.title=Über JADX
|
||||
|
||||
preferences.title=Einstellungen
|
||||
preferences.deobfuscation=Deobfuscation
|
||||
preferences.editor=Editor
|
||||
#preferences.appearance=Appearance
|
||||
preferences.decompile=Dekompilierung
|
||||
preferences.project=Projekt
|
||||
preferences.other=Andere
|
||||
@@ -139,6 +139,7 @@ preferences.cfg=Methoden generieren CFG-Grafiken (im 'Punkt'-Format)
|
||||
preferences.raw_cfg=RAW CFG-Grafiken generieren
|
||||
preferences.font=Schrift ändern
|
||||
#preferences.smali_font=
|
||||
#preferences.laf_theme=Theme
|
||||
preferences.theme=Thema ändern
|
||||
preferences.start_jobs=Autom. Hintergrunddekompilierung starten
|
||||
preferences.select_font=Ändern
|
||||
|
||||
@@ -113,7 +113,7 @@ about_dialog.title=About JADX
|
||||
|
||||
preferences.title=Preferences
|
||||
preferences.deobfuscation=Deobfuscation
|
||||
preferences.editor=Editor
|
||||
preferences.appearance=Appearance
|
||||
preferences.decompile=Decompilation
|
||||
preferences.project=Project
|
||||
preferences.other=Other
|
||||
@@ -139,6 +139,7 @@ preferences.cfg=Generate methods CFG graphs (in 'dot' format)
|
||||
preferences.raw_cfg=Generate RAW CFG graphs
|
||||
preferences.font=Editor font
|
||||
preferences.smali_font=Smali Editor font
|
||||
preferences.laf_theme=Theme
|
||||
preferences.theme=Editor theme
|
||||
preferences.start_jobs=Auto start background decompilation
|
||||
preferences.select_font=Change
|
||||
|
||||
@@ -113,7 +113,7 @@ about_dialog.title=Sobre JADX
|
||||
|
||||
preferences.title=Preferencias
|
||||
preferences.deobfuscation=Desofuscación
|
||||
preferences.editor=Editor
|
||||
#preferences.appearance=Appearance
|
||||
preferences.decompile=Descompilación
|
||||
#preferences.project=
|
||||
preferences.other=Otros
|
||||
@@ -139,6 +139,7 @@ preferences.cfg=Generar methods CFG graphs (in 'dot' format)
|
||||
preferences.raw_cfg=Generate RAW CFG graphs
|
||||
preferences.font=Fuente del editor
|
||||
#preferences.smali_font=
|
||||
#preferences.laf_theme=Theme
|
||||
preferences.theme=Tema del editor
|
||||
preferences.start_jobs=Inicio autom. descompilación de fondo
|
||||
preferences.select_font=Seleccionar
|
||||
|
||||
@@ -113,7 +113,7 @@ about_dialog.title=JADX 정보
|
||||
|
||||
preferences.title=설정
|
||||
preferences.deobfuscation=난독화 해제
|
||||
preferences.editor=에디터
|
||||
#preferences.appearance=Appearance
|
||||
preferences.decompile=디컴파일
|
||||
preferences.project=프로젝트
|
||||
preferences.other=기타
|
||||
@@ -139,6 +139,7 @@ preferences.cfg=메소드 CFG 그래프 생성 ('dot' 포맷)
|
||||
preferences.raw_cfg=RAW CFG 그래프 생성
|
||||
preferences.font=에디터 글씨체
|
||||
preferences.smali_font=Smali 에디터 글씨체
|
||||
#preferences.laf_theme=Theme
|
||||
preferences.theme=에디터 테마
|
||||
preferences.start_jobs=백그라운드에서 디컴파일 자동 시작
|
||||
preferences.select_font=변경
|
||||
|
||||
@@ -113,7 +113,7 @@ about_dialog.title=关于 JADX
|
||||
|
||||
preferences.title=首选项
|
||||
preferences.deobfuscation=反混淆
|
||||
preferences.editor=编辑器
|
||||
#preferences.appearance=Appearance
|
||||
preferences.decompile=反编译
|
||||
preferences.project=项目
|
||||
preferences.other=其他
|
||||
@@ -139,6 +139,7 @@ preferences.cfg=生成方法的 CFG 图(以 .dot 格式保存)
|
||||
preferences.raw_cfg=生成原始的 CFG 图
|
||||
preferences.font=编辑器字体
|
||||
#preferences.smali_font=
|
||||
#preferences.laf_theme=Theme
|
||||
preferences.theme=编辑器主题
|
||||
preferences.start_jobs=自动进行后台反编译
|
||||
preferences.select_font=更改
|
||||
|
||||
Reference in New Issue
Block a user