gui: add log viewer
This commit is contained in:
@@ -3,6 +3,7 @@ package jadx.gui;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.settings.JadxSettingsAdapter;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.LogCollector;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
@@ -15,6 +16,7 @@ public class JadxGUI {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
LogCollector.register();
|
||||
final JadxSettings jadxArgs = JadxSettingsAdapter.load();
|
||||
// overwrite loaded settings by command line arguments
|
||||
if (!jadxArgs.processArgs(args)) {
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import jadx.gui.utils.LogCollector;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Container;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
|
||||
class LogViewer extends JDialog {
|
||||
private static final long serialVersionUID = -2188700277429054641L;
|
||||
private static final Level[] LEVEL_ITEMS = {Level.DEBUG, Level.INFO, Level.WARN, Level.ERROR};
|
||||
|
||||
private static Level level = Level.WARN;
|
||||
private RSyntaxTextArea textPane;
|
||||
|
||||
public LogViewer() {
|
||||
initUI();
|
||||
registerLogListener();
|
||||
}
|
||||
|
||||
public final void initUI() {
|
||||
textPane = new RSyntaxTextArea();
|
||||
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();
|
||||
}
|
||||
});
|
||||
JLabel levelLabel = new JLabel(NLS.str("log.level"));
|
||||
levelLabel.setLabelFor(cb);
|
||||
controlPane.add(levelLabel);
|
||||
controlPane.add(cb);
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(textPane);
|
||||
|
||||
JButton close = new JButton(NLS.str("tabs.close"));
|
||||
close.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
close();
|
||||
}
|
||||
});
|
||||
close.setAlignmentX(0.5f);
|
||||
|
||||
Container contentPane = getContentPane();
|
||||
contentPane.add(controlPane, BorderLayout.PAGE_START);
|
||||
contentPane.add(scrollPane, BorderLayout.CENTER);
|
||||
contentPane.add(close, BorderLayout.PAGE_END);
|
||||
|
||||
setTitle("Log Viewer");
|
||||
pack();
|
||||
setSize(800, 600);
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
setModalityType(ModalityType.MODELESS);
|
||||
setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
private void registerLogListener() {
|
||||
LogCollector logCollector = LogCollector.getInstance();
|
||||
logCollector.resetListener();
|
||||
textPane.setText("");
|
||||
logCollector.registerListener(new LogCollector.ILogListener() {
|
||||
@Override
|
||||
public Level getFilterLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppend(final String logStr) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
textPane.append(logStr);
|
||||
textPane.updateUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void close() {
|
||||
LogCollector.getInstance().resetListener();
|
||||
dispose();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new LogViewer().setVisible(true);
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,7 @@ public class MainWindow extends JFrame {
|
||||
private static final ImageIcon ICON_FORWARD = Utils.openIcon("icon_forward");
|
||||
private static final ImageIcon ICON_PREF = Utils.openIcon("wrench");
|
||||
private static final ImageIcon ICON_DEOBF = Utils.openIcon("lock_edit");
|
||||
private static final ImageIcon ICON_LOG = Utils.openIcon("report");
|
||||
|
||||
private final JadxWrapper wrapper;
|
||||
private final JadxSettings settings;
|
||||
@@ -375,6 +376,19 @@ public class MainWindow extends JFrame {
|
||||
};
|
||||
find.addActionListener(findAction);
|
||||
|
||||
JMenu tools = new JMenu(NLS.str("menu.tools"));
|
||||
tools.setMnemonic(KeyEvent.VK_T);
|
||||
|
||||
JMenuItem logItem = new JMenuItem(NLS.str("menu.log"), ICON_LOG);
|
||||
ActionListener logAction = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new LogViewer().setVisible(true);
|
||||
}
|
||||
};
|
||||
logItem.addActionListener(logAction);
|
||||
tools.add(logItem);
|
||||
|
||||
JMenu help = new JMenu(NLS.str("menu.help"));
|
||||
help.setMnemonic(KeyEvent.VK_H);
|
||||
|
||||
@@ -390,6 +404,7 @@ public class MainWindow extends JFrame {
|
||||
menuBar.add(file);
|
||||
menuBar.add(view);
|
||||
menuBar.add(nav);
|
||||
menuBar.add(tools);
|
||||
menuBar.add(help);
|
||||
setJMenuBar(menuBar);
|
||||
|
||||
@@ -470,6 +485,10 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
JButton logBtn = new JButton(ICON_LOG);
|
||||
logBtn.setToolTipText(NLS.str("menu.log"));
|
||||
logBtn.addActionListener(logAction);
|
||||
|
||||
updateLink = new Link("", JadxUpdate.JADX_RELEASES_URL);
|
||||
updateLink.setVisible(false);
|
||||
|
||||
@@ -495,6 +514,9 @@ public class MainWindow extends JFrame {
|
||||
toolbar.add(deobfToggleBtn);
|
||||
toolbar.addSeparator();
|
||||
|
||||
toolbar.add(logBtn);
|
||||
toolbar.addSeparator();
|
||||
|
||||
toolbar.add(prefButton);
|
||||
toolbar.addSeparator();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.NameIndex;
|
||||
import jadx.gui.utils.Position;
|
||||
import jadx.gui.utils.TextStandardActions;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
@@ -198,7 +199,7 @@ public class SearchDialog extends JDialog {
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list,
|
||||
Object obj, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
Object obj, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
if (!(obj instanceof JNode)) {
|
||||
return null;
|
||||
}
|
||||
@@ -317,7 +318,7 @@ public class SearchDialog extends JDialog {
|
||||
setSize(700, 500);
|
||||
setLocationRelativeTo(null);
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
setModalityType(ModalityType.APPLICATION_MODAL);
|
||||
setModalityType(ModalityType.MODELESS);
|
||||
}
|
||||
|
||||
private JCheckBox makeOptionsCheckBox(String name, final SearchOptions opt) {
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package jadx.gui.utils;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.PatternLayout;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Layout;
|
||||
import ch.qos.logback.core.read.CyclicBufferAppender;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LogCollector extends CyclicBufferAppender<ILoggingEvent> {
|
||||
private static LogCollector instance = new LogCollector();
|
||||
|
||||
public static LogCollector getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
LoggerContext loggerContext = rootLogger.getLoggerContext();
|
||||
|
||||
PatternLayout layout = new PatternLayout();
|
||||
layout.setContext(loggerContext);
|
||||
layout.setPattern("%-5level: %msg%n");
|
||||
layout.start();
|
||||
|
||||
instance.setContext(loggerContext);
|
||||
instance.setLayout(layout);
|
||||
instance.start();
|
||||
|
||||
rootLogger.addAppender(instance);
|
||||
}
|
||||
|
||||
public interface ILogListener {
|
||||
|
||||
Level getFilterLevel();
|
||||
|
||||
void onAppend(String logStr);
|
||||
}
|
||||
|
||||
private Layout<ILoggingEvent> layout;
|
||||
|
||||
@Nullable
|
||||
private ILogListener listener;
|
||||
|
||||
public LogCollector() {
|
||||
setName("LogCollector");
|
||||
setMaxSize(50000);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(ILoggingEvent event) {
|
||||
super.append(event);
|
||||
if (listener != null
|
||||
&& event.getLevel().isGreaterOrEqual(listener.getFilterLevel())) {
|
||||
synchronized (this) {
|
||||
listener.onAppend(layout.doLayout(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setLayout(Layout<ILoggingEvent> layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
public void registerListener(@NotNull ILogListener listener) {
|
||||
this.listener = listener;
|
||||
synchronized (this) {
|
||||
listener.onAppend(init(listener.getFilterLevel()));
|
||||
}
|
||||
}
|
||||
|
||||
public void resetListener() {
|
||||
this.listener = null;
|
||||
}
|
||||
|
||||
private String init(Level filterLevel) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int length = getLength();
|
||||
for (int i = 0; i < length; i++) {
|
||||
ILoggingEvent event = get(i);
|
||||
if (event.getLevel().isGreaterOrEqual(filterLevel)) {
|
||||
sb.append(layout.doLayout(event));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user