feat(gui): allow to dock log viewer, new filter modes
This commit is contained in:
@@ -14,10 +14,11 @@ dependencies {
|
||||
|
||||
// jadx-script autocomplete support
|
||||
implementation(project(":jadx-plugins::jadx-script:jadx-script-ide"))
|
||||
implementation(project(":jadx-plugins::jadx-script:jadx-script-runtime"))
|
||||
implementation 'org.jetbrains.kotlin:kotlin-scripting-common:1.7.20'
|
||||
implementation 'com.fifesoft:autocomplete:3.3.0'
|
||||
|
||||
// use ktlint for lint and format jadx scripts
|
||||
// use KtLint for format and check jadx scripts
|
||||
implementation 'com.pinterest.ktlint:ktlint-core:0.47.1'
|
||||
implementation 'com.pinterest.ktlint:ktlint-ruleset-standard:0.47.1'
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.cli.LogHelper;
|
||||
import jadx.gui.logs.LogCollector;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.settings.JadxSettingsAdapter;
|
||||
import jadx.gui.ui.ExceptionDialog;
|
||||
@@ -13,7 +14,6 @@ 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;
|
||||
|
||||
public class JadxGUI {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxGUI.class);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
public interface ILogListener {
|
||||
void onAppend(LogEvent logEvent);
|
||||
|
||||
void onReload();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import jadx.gui.ui.panel.IssuesPanel;
|
||||
import jadx.gui.utils.rx.DebounceUpdate;
|
||||
|
||||
public class IssuesListener implements ILogListener {
|
||||
private final IssuesPanel issuesPanel;
|
||||
private final DebounceUpdate updater;
|
||||
|
||||
private int errors = 0;
|
||||
private int warnings = 0;
|
||||
|
||||
public IssuesListener(IssuesPanel issuesPanel) {
|
||||
this.issuesPanel = issuesPanel;
|
||||
this.updater = new DebounceUpdate(500, this::onUpdate);
|
||||
}
|
||||
|
||||
private void onUpdate() {
|
||||
SwingUtilities.invokeLater(() -> issuesPanel.onUpdate(errors, warnings));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppend(LogEvent logEvent) {
|
||||
switch (logEvent.getLevel().toInt()) {
|
||||
case Level.ERROR_INT:
|
||||
errors++;
|
||||
updater.requestUpdate();
|
||||
break;
|
||||
|
||||
case Level.WARN_INT:
|
||||
warnings++;
|
||||
updater.requestUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
errors = 0;
|
||||
warnings = 0;
|
||||
updater.requestUpdate();
|
||||
}
|
||||
|
||||
public int getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public int getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.gui.utils.logs;
|
||||
package jadx.gui.logs;
|
||||
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.ArrayDeque;
|
||||
@@ -0,0 +1,51 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
import static jadx.plugins.script.runtime.JadxScriptTemplateKt.JADX_SCRIPT_LOG_PREFIX;
|
||||
|
||||
class LogAppender implements ILogListener {
|
||||
private final LogOptions options;
|
||||
private final RSyntaxTextArea textArea;
|
||||
|
||||
public LogAppender(LogOptions options, RSyntaxTextArea textArea) {
|
||||
this.options = options;
|
||||
this.textArea = textArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppend(LogEvent logEvent) {
|
||||
if (accept(logEvent)) {
|
||||
UiUtils.uiRun(() -> textArea.append(logEvent.getMsg()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
UiUtils.uiRunAndWait(() -> textArea.append(StringUtils.repeat('=', 100) + '\n'));
|
||||
}
|
||||
|
||||
private boolean accept(LogEvent logEvent) {
|
||||
boolean byLevel = logEvent.getLevel().isGreaterOrEqual(options.getLogLevel());
|
||||
if (!byLevel) {
|
||||
return false;
|
||||
}
|
||||
switch (options.getMode()) {
|
||||
case ALL:
|
||||
return true;
|
||||
|
||||
case ALL_SCRIPTS:
|
||||
return logEvent.getLoggerName().startsWith(JADX_SCRIPT_LOG_PREFIX);
|
||||
|
||||
case CURRENT_SCRIPT:
|
||||
return logEvent.getLoggerName().equals(options.getFilter());
|
||||
|
||||
default:
|
||||
throw new JadxRuntimeException("Unexpected log mode: " + options.getMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.AppenderBase;
|
||||
import ch.qos.logback.core.Layout;
|
||||
|
||||
public class LogCollector extends AppenderBase<ILoggingEvent> {
|
||||
public static final int BUFFER_SIZE = 5000;
|
||||
|
||||
private static final 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);
|
||||
}
|
||||
|
||||
private final List<ILogListener> listeners = new ArrayList<>();
|
||||
private final Queue<LogEvent> buffer = new LimitedQueue<>(BUFFER_SIZE);
|
||||
|
||||
private Layout<ILoggingEvent> layout;
|
||||
|
||||
public LogCollector() {
|
||||
setName("LogCollector");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void append(ILoggingEvent event) {
|
||||
String msg = layout.doLayout(event);
|
||||
LogEvent logEvent = new LogEvent(event.getLevel(), event.getLoggerName(), msg);
|
||||
buffer.offer(logEvent);
|
||||
listeners.forEach(l -> l.onAppend(logEvent));
|
||||
}
|
||||
|
||||
private void setLayout(Layout<ILoggingEvent> layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
public synchronized void registerListener(ILogListener listener) {
|
||||
listeners.add(listener);
|
||||
buffer.forEach(listener::onAppend);
|
||||
}
|
||||
|
||||
public synchronized boolean removeListener(@Nullable ILogListener listener) {
|
||||
if (listener == null) {
|
||||
return false;
|
||||
}
|
||||
return this.listeners.removeIf(l -> l == listener);
|
||||
}
|
||||
|
||||
public synchronized boolean removeListenerByClass(Class<?> listenerCls) {
|
||||
return this.listeners.removeIf(l -> l.getClass().equals(listenerCls));
|
||||
}
|
||||
|
||||
public synchronized void reset() {
|
||||
buffer.clear();
|
||||
listeners.forEach(ILogListener::onReload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
public final class LogEvent {
|
||||
private final Level level;
|
||||
private final String loggerName;
|
||||
private final String msg;
|
||||
|
||||
LogEvent(Level level, String loggerName, String msg) {
|
||||
this.level = level;
|
||||
this.loggerName = loggerName;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getLoggerName() {
|
||||
return loggerName;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return level + ": " + loggerName + " - " + msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public enum LogMode {
|
||||
ALL,
|
||||
ALL_SCRIPTS,
|
||||
CURRENT_SCRIPT;
|
||||
|
||||
private static final String[] NLS_STRINGS = StringUtils.split(NLS.str("log_viewer.modes"), '|');
|
||||
|
||||
public String getLocalizedName() {
|
||||
return NLS_STRINGS[this.ordinal()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getLocalizedName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
import static jadx.plugins.script.runtime.JadxScriptTemplateKt.JADX_SCRIPT_LOG_PREFIX;
|
||||
|
||||
public class LogOptions {
|
||||
|
||||
/**
|
||||
* Store latest requested log options
|
||||
*/
|
||||
private static LogOptions current = new LogOptions(LogMode.ALL, Level.INFO, null);
|
||||
|
||||
public static LogOptions allWithLevel(@Nullable Level logLevel) {
|
||||
Level level = Utils.getOrElse(logLevel, current.getLogLevel());
|
||||
return store(new LogOptions(LogMode.ALL, level, null));
|
||||
}
|
||||
|
||||
public static LogOptions forLevel(@Nullable Level logLevel) {
|
||||
Level level = Utils.getOrElse(logLevel, current.getLogLevel());
|
||||
return store(new LogOptions(current.getMode(), level, current.getFilter()));
|
||||
}
|
||||
|
||||
public static LogOptions forMode(LogMode mode) {
|
||||
return store(new LogOptions(mode, current.getLogLevel(), current.getFilter()));
|
||||
}
|
||||
|
||||
public static LogOptions forScript(String scriptName) {
|
||||
String filter = JADX_SCRIPT_LOG_PREFIX + scriptName;
|
||||
return store(new LogOptions(LogMode.CURRENT_SCRIPT, current.getLogLevel(), filter));
|
||||
}
|
||||
|
||||
public static LogOptions current() {
|
||||
return current;
|
||||
}
|
||||
|
||||
private static LogOptions store(LogOptions logOptions) {
|
||||
current = logOptions;
|
||||
return logOptions;
|
||||
}
|
||||
|
||||
private final LogMode mode;
|
||||
private final Level logLevel;
|
||||
private final @Nullable String filter;
|
||||
|
||||
private LogOptions(LogMode mode, Level logLevel, @Nullable String filter) {
|
||||
this.mode = mode;
|
||||
this.logLevel = logLevel;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public LogMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public Level getLogLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
public @Nullable String getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LogOptions{mode=" + mode + ", logLevel=" + logLevel + ", filter='" + filter + '\'' + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package jadx.gui.logs;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.treemodel.JInputScript;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.codearea.AbstractCodeArea;
|
||||
import jadx.gui.ui.panel.ContentPanel;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class LogPanel extends JPanel {
|
||||
private static final long serialVersionUID = -8077649118322056081L;
|
||||
|
||||
private static final Level[] LEVEL_ITEMS = { Level.DEBUG, Level.INFO, Level.WARN, Level.ERROR };
|
||||
|
||||
private final MainWindow mainWindow;
|
||||
private final Runnable dockAction;
|
||||
private final Runnable hideAction;
|
||||
|
||||
private RSyntaxTextArea textPane;
|
||||
private JComboBox<LogMode> modeCb;
|
||||
private JComboBox<Level> levelCb;
|
||||
|
||||
private ChangeListener activeTabListener;
|
||||
|
||||
public LogPanel(MainWindow mainWindow, LogOptions logOptions, Runnable dockAction, Runnable hideAction) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.dockAction = dockAction;
|
||||
this.hideAction = hideAction;
|
||||
initUI(logOptions);
|
||||
applyLogOptions(logOptions);
|
||||
}
|
||||
|
||||
public void applyLogOptions(LogOptions logOptions) {
|
||||
if (logOptions.getMode() == LogMode.CURRENT_SCRIPT) {
|
||||
String scriptName = getCurrentScriptName();
|
||||
if (scriptName != null) {
|
||||
logOptions = LogOptions.forScript(scriptName);
|
||||
}
|
||||
registerActiveTabListener();
|
||||
} else {
|
||||
removeActiveTabListener();
|
||||
}
|
||||
if (modeCb.getSelectedItem() != logOptions.getMode()) {
|
||||
modeCb.setSelectedItem(logOptions.getMode());
|
||||
}
|
||||
if (levelCb.getSelectedItem() != logOptions.getLogLevel()) {
|
||||
levelCb.setSelectedItem(logOptions.getLogLevel());
|
||||
}
|
||||
registerLogListener(logOptions);
|
||||
}
|
||||
|
||||
public void loadSettings() {
|
||||
AbstractCodeArea.loadCommonSettings(mainWindow, textPane);
|
||||
}
|
||||
|
||||
private void initUI(LogOptions logOptions) {
|
||||
JadxSettings settings = mainWindow.getSettings();
|
||||
textPane = AbstractCodeArea.getDefaultArea(mainWindow);
|
||||
textPane.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
|
||||
|
||||
modeCb = new JComboBox<>(LogMode.values());
|
||||
modeCb.setSelectedItem(logOptions.getMode());
|
||||
modeCb.addActionListener(e -> applyLogOptions(LogOptions.forMode((LogMode) modeCb.getSelectedItem())));
|
||||
JLabel modeLabel = new JLabel(NLS.str("log_viewer.mode"));
|
||||
modeLabel.setLabelFor(modeCb);
|
||||
|
||||
levelCb = new JComboBox<>(LEVEL_ITEMS);
|
||||
levelCb.setSelectedItem(logOptions.getLogLevel());
|
||||
levelCb.addActionListener(e -> applyLogOptions(LogOptions.forLevel((Level) levelCb.getSelectedItem())));
|
||||
JLabel levelLabel = new JLabel(NLS.str("log_viewer.log_level"));
|
||||
levelLabel.setLabelFor(levelCb);
|
||||
|
||||
JButton clearBtn = new JButton(NLS.str("log_viewer.clear"));
|
||||
clearBtn.addActionListener(ev -> {
|
||||
LogCollector.getInstance().reset();
|
||||
textPane.setText("");
|
||||
});
|
||||
|
||||
JButton dockBtn = new JButton(NLS.str(settings.isDockLogViewer() ? "log_viewer.undock" : "log_viewer.dock"));
|
||||
dockBtn.addActionListener(ev -> dockAction.run());
|
||||
|
||||
JButton hideBtn = new JButton(NLS.str("log_viewer.hide"));
|
||||
hideBtn.addActionListener(ev -> hideAction.run());
|
||||
|
||||
JPanel start = new JPanel();
|
||||
start.setLayout(new BoxLayout(start, BoxLayout.LINE_AXIS));
|
||||
start.add(modeLabel);
|
||||
start.add(Box.createRigidArea(new Dimension(5, 0)));
|
||||
start.add(modeCb);
|
||||
start.add(Box.createRigidArea(new Dimension(15, 0)));
|
||||
start.add(levelLabel);
|
||||
start.add(Box.createRigidArea(new Dimension(5, 0)));
|
||||
start.add(levelCb);
|
||||
start.add(Box.createRigidArea(new Dimension(5, 0)));
|
||||
|
||||
JPanel end = new JPanel();
|
||||
end.setLayout(new BoxLayout(end, BoxLayout.LINE_AXIS));
|
||||
end.add(clearBtn);
|
||||
end.add(Box.createRigidArea(new Dimension(15, 0)));
|
||||
end.add(dockBtn);
|
||||
end.add(Box.createRigidArea(new Dimension(15, 0)));
|
||||
end.add(hideBtn);
|
||||
|
||||
JPanel controlPane = new JPanel();
|
||||
controlPane.setLayout(new BorderLayout());
|
||||
controlPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
controlPane.add(start, BorderLayout.LINE_START);
|
||||
controlPane.add(end, BorderLayout.LINE_END);
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(textPane);
|
||||
|
||||
setLayout(new BorderLayout(5, 5));
|
||||
add(controlPane, BorderLayout.PAGE_START);
|
||||
add(scrollPane, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private void registerLogListener(LogOptions logOptions) {
|
||||
LogCollector logCollector = LogCollector.getInstance();
|
||||
logCollector.removeListenerByClass(LogAppender.class);
|
||||
textPane.setText("");
|
||||
logCollector.registerListener(new LogAppender(logOptions, textPane));
|
||||
}
|
||||
|
||||
private @Nullable String getCurrentScriptName() {
|
||||
ContentPanel selectedCodePanel = mainWindow.getTabbedPane().getSelectedCodePanel();
|
||||
if (selectedCodePanel != null) {
|
||||
JNode node = selectedCodePanel.getNode();
|
||||
if (node instanceof JInputScript) {
|
||||
return node.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private synchronized void registerActiveTabListener() {
|
||||
removeActiveTabListener();
|
||||
activeTabListener = e -> {
|
||||
String scriptName = getCurrentScriptName();
|
||||
if (scriptName != null) {
|
||||
applyLogOptions(LogOptions.forScript(scriptName));
|
||||
}
|
||||
};
|
||||
mainWindow.getTabbedPane().addChangeListener(activeTabListener);
|
||||
}
|
||||
|
||||
private synchronized void removeActiveTabListener() {
|
||||
if (activeTabListener != null) {
|
||||
mainWindow.getTabbedPane().removeChangeListener(activeTabListener);
|
||||
activeTabListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
LogCollector.getInstance().removeListenerByClass(LogAppender.class);
|
||||
removeActiveTabListener();
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,10 @@ import org.slf4j.LoggerFactory;
|
||||
import com.pinterest.ktlint.core.LintError;
|
||||
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic;
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic.Severity;
|
||||
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.logs.LogOptions;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.settings.LineNumbersMode;
|
||||
import jadx.gui.treemodel.JInputScript;
|
||||
@@ -40,17 +42,18 @@ import jadx.gui.utils.ui.NodeLabel;
|
||||
import jadx.plugins.script.ide.ScriptAnalyzeResult;
|
||||
import jadx.plugins.script.ide.ScriptCompiler;
|
||||
|
||||
import static jadx.plugins.script.runtime.JadxScriptTemplateKt.JADX_SCRIPT_LOG_PREFIX;
|
||||
|
||||
public class ScriptContentPanel extends AbstractCodeContentPanel {
|
||||
private static final long serialVersionUID = 6575696321112417513L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ScriptContentPanel.class);
|
||||
|
||||
private final ScriptCodeArea scriptArea;
|
||||
private final SearchBar searchBar;
|
||||
private final RTextScrollPane codeScrollPane;
|
||||
private final JPanel actionPanel;
|
||||
private final JLabel resultLabel;
|
||||
private final ScriptErrorService errorService;
|
||||
private final Logger scriptLog;
|
||||
|
||||
public ScriptContentPanel(TabbedPane panel, JInputScript scriptNode) {
|
||||
super(panel, scriptNode);
|
||||
@@ -60,6 +63,7 @@ public class ScriptContentPanel extends AbstractCodeContentPanel {
|
||||
actionPanel = buildScriptActionsPanel();
|
||||
searchBar = new SearchBar(scriptArea);
|
||||
codeScrollPane = new RTextScrollPane(scriptArea);
|
||||
scriptLog = LoggerFactory.getLogger(JADX_SCRIPT_LOG_PREFIX + scriptNode.getName());
|
||||
|
||||
initUI();
|
||||
applySettings();
|
||||
@@ -136,7 +140,7 @@ public class ScriptContentPanel extends AbstractCodeContentPanel {
|
||||
wrapper.resetGuiPluginsContext();
|
||||
wrapper.getDecompiler().reloadPasses();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Passes reload failed", e);
|
||||
scriptLog.error("Passes reload failed", e);
|
||||
}
|
||||
}, taskStatus -> {
|
||||
tabbedPane.reloadInactiveTabs();
|
||||
@@ -153,12 +157,16 @@ public class ScriptContentPanel extends AbstractCodeContentPanel {
|
||||
ScriptCompiler scriptCompiler = new ScriptCompiler(fileName);
|
||||
ScriptAnalyzeResult result = scriptCompiler.analyze(code, scriptArea.getCaretPosition());
|
||||
List<ScriptDiagnostic> issues = result.getIssues();
|
||||
boolean success = true;
|
||||
for (ScriptDiagnostic issue : issues) {
|
||||
LOG.warn("Compiler issue: {}", issue);
|
||||
Severity severity = issue.getSeverity();
|
||||
if (severity == Severity.ERROR || severity == Severity.FATAL) {
|
||||
scriptLog.error("{}", issue.render(false, true, true, true));
|
||||
success = false;
|
||||
} else {
|
||||
scriptLog.warn("Compiler issue: {}", issue);
|
||||
}
|
||||
}
|
||||
boolean success = issues.stream().map(ScriptDiagnostic::getSeverity)
|
||||
.noneMatch(s -> s == ScriptDiagnostic.Severity.ERROR || s == ScriptDiagnostic.Severity.FATAL);
|
||||
|
||||
List<LintError> lintErrs = Collections.emptyList();
|
||||
if (success) {
|
||||
lintErrs = getLintIssues(code, fileName);
|
||||
@@ -170,12 +178,13 @@ public class ScriptContentPanel extends AbstractCodeContentPanel {
|
||||
errorService.apply();
|
||||
if (!success) {
|
||||
resultLabel.setText("Compiler issues: " + issues.size());
|
||||
getTabbedPane().getMainWindow().showLogViewer(LogOptions.forScript(getNode().getName()));
|
||||
} else if (!lintErrs.isEmpty()) {
|
||||
resultLabel.setText("Lint issues: " + lintErrs.size());
|
||||
}
|
||||
return success;
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Failed to check code", e);
|
||||
scriptLog.error("Failed to check code", e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -184,11 +193,12 @@ public class ScriptContentPanel extends AbstractCodeContentPanel {
|
||||
try {
|
||||
List<LintError> lintErrs = KtLintUtils.INSTANCE.lint(code, fileName);
|
||||
for (LintError error : lintErrs) {
|
||||
LOG.warn("Lint issue: {}", error);
|
||||
scriptLog.warn("Lint issue: {} ({}:{})(ruleId={})",
|
||||
error.getDetail(), error.getLine(), error.getCol(), error.getRuleId());
|
||||
}
|
||||
return lintErrs;
|
||||
} catch (Throwable e) { // can throw initialization error
|
||||
LOG.warn("KtLint failed", e);
|
||||
scriptLog.warn("KtLint failed", e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -205,7 +215,7 @@ public class ScriptContentPanel extends AbstractCodeContentPanel {
|
||||
errorService.clearErrors();
|
||||
}
|
||||
} catch (Throwable e) { // can throw initialization error
|
||||
LOG.error("Failed to reformat code", e);
|
||||
scriptLog.error("Failed to reformat code", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,8 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
*/
|
||||
private int treeWidth = 130;
|
||||
|
||||
private boolean dockLogViewer = true;
|
||||
|
||||
private int settingsVersion = 0;
|
||||
|
||||
@JadxSettingsAdapter.GsonExclude
|
||||
@@ -686,6 +688,15 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
this.jumpOnDoubleClick = jumpOnDoubleClick;
|
||||
}
|
||||
|
||||
public boolean isDockLogViewer() {
|
||||
return dockLogViewer;
|
||||
}
|
||||
|
||||
public void setDockLogViewer(boolean dockLogViewer) {
|
||||
this.dockLogViewer = dockLogViewer;
|
||||
partialSync(settings -> this.dockLogViewer = dockLogViewer);
|
||||
}
|
||||
|
||||
private void upgradeSettings(int fromVersion) {
|
||||
LOG.debug("upgrade settings from version: {} to {}", fromVersion, CURRENT_SETTINGS_VERSION);
|
||||
if (fromVersion == 0) {
|
||||
|
||||
@@ -33,15 +33,12 @@ import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
@@ -53,7 +50,6 @@ import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
@@ -65,8 +61,6 @@ import javax.swing.JTree;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.WindowConstants;
|
||||
import javax.swing.event.MenuEvent;
|
||||
import javax.swing.event.MenuListener;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeWillExpandListener;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
@@ -105,6 +99,9 @@ import jadx.gui.jobs.BackgroundExecutor;
|
||||
import jadx.gui.jobs.DecompileTask;
|
||||
import jadx.gui.jobs.ExportTask;
|
||||
import jadx.gui.jobs.TaskStatus;
|
||||
import jadx.gui.logs.LogCollector;
|
||||
import jadx.gui.logs.LogOptions;
|
||||
import jadx.gui.logs.LogPanel;
|
||||
import jadx.gui.plugins.quark.QuarkDialog;
|
||||
import jadx.gui.settings.JadxProject;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
@@ -130,6 +127,7 @@ import jadx.gui.ui.panel.ContentPanel;
|
||||
import jadx.gui.ui.panel.IssuesPanel;
|
||||
import jadx.gui.ui.panel.JDebuggerPanel;
|
||||
import jadx.gui.ui.panel.ProgressPanel;
|
||||
import jadx.gui.ui.popupmenu.RecentProjectsMenuListener;
|
||||
import jadx.gui.ui.treenodes.StartPageNode;
|
||||
import jadx.gui.ui.treenodes.SummaryNode;
|
||||
import jadx.gui.update.JadxUpdate;
|
||||
@@ -145,7 +143,6 @@ import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.SystemInfo;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
import jadx.gui.utils.fileswatcher.LiveReloadWorker;
|
||||
import jadx.gui.utils.logs.LogCollector;
|
||||
import jadx.gui.utils.ui.ActionHandler;
|
||||
import jadx.gui.utils.ui.NodeLabel;
|
||||
import jadx.plugins.mappings.save.MappingExporter;
|
||||
@@ -197,8 +194,10 @@ public class MainWindow extends JFrame {
|
||||
private MappingFormat currentMappingFormat;
|
||||
private boolean renamesChanged = false;
|
||||
|
||||
private JPanel mainPanel;
|
||||
private JSplitPane splitPane;
|
||||
private transient JPanel mainPanel;
|
||||
private transient JSplitPane treeSplitPane;
|
||||
private transient JSplitPane rightSplitPane;
|
||||
private transient JSplitPane bottomSplitPane;
|
||||
|
||||
private JTree tree;
|
||||
private DefaultTreeModel treeModel;
|
||||
@@ -221,8 +220,9 @@ public class MainWindow extends JFrame {
|
||||
private transient ProgressPanel progressPane;
|
||||
private transient Theme editorTheme;
|
||||
|
||||
private JDebuggerPanel debuggerPanel;
|
||||
private JSplitPane verticalSplitter;
|
||||
private transient IssuesPanel issuesPanel;
|
||||
private transient @Nullable LogPanel logPanel;
|
||||
private transient @Nullable JDebuggerPanel debuggerPanel;
|
||||
|
||||
private final List<ILoadListener> loadListeners = new ArrayList<>();
|
||||
private boolean loaded;
|
||||
@@ -238,6 +238,7 @@ public class MainWindow extends JFrame {
|
||||
|
||||
resetCache();
|
||||
FontUtils.registerBundledFonts();
|
||||
setEditorTheme(settings.getEditorThemePath());
|
||||
initUI();
|
||||
this.backgroundExecutor = new BackgroundExecutor(settings, progressPane);
|
||||
initMenuAndToolbar();
|
||||
@@ -252,7 +253,7 @@ public class MainWindow extends JFrame {
|
||||
public void init() {
|
||||
pack();
|
||||
setLocationAndPosition();
|
||||
splitPane.setDividerLocation(settings.getTreeWidth());
|
||||
treeSplitPane.setDividerLocation(settings.getTreeWidth());
|
||||
heapUsageBar.setVisible(settings.isShowHeapUsageBar());
|
||||
setVisible(true);
|
||||
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
|
||||
@@ -634,7 +635,7 @@ public class MainWindow extends JFrame {
|
||||
if (!wrapper.getClasses().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int errors = LogCollector.getInstance().getErrors();
|
||||
int errors = issuesPanel.getErrorsCount();
|
||||
if (errors > 0) {
|
||||
int result = JOptionPane.showConfirmDialog(this,
|
||||
NLS.str("message.load_errors", errors),
|
||||
@@ -642,7 +643,7 @@ public class MainWindow extends JFrame {
|
||||
JOptionPane.OK_CANCEL_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
LogViewerDialog.openWithLevel(this, Level.ERROR);
|
||||
showLogViewer(LogOptions.allWithLevel(Level.ERROR));
|
||||
}
|
||||
} else {
|
||||
UiUtils.showMessageBox(this, NLS.str("message.no_classes"));
|
||||
@@ -1101,7 +1102,7 @@ public class MainWindow extends JFrame {
|
||||
exportAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_E, UiUtils.ctrlButton() | KeyEvent.SHIFT_DOWN_MASK));
|
||||
|
||||
JMenu recentProjects = new JMenu(NLS.str("menu.recent_projects"));
|
||||
recentProjects.addMenuListener(new RecentProjectsMenuListener(recentProjects));
|
||||
recentProjects.addMenuListener(new RecentProjectsMenuListener(this, recentProjects));
|
||||
|
||||
Action prefsAction = new AbstractAction(NLS.str("menu.preferences"), ICON_PREF) {
|
||||
@Override
|
||||
@@ -1140,6 +1141,10 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
JCheckBoxMenuItem dockLog = new JCheckBoxMenuItem(NLS.str("menu.dock_log"));
|
||||
dockLog.setState(settings.isDockLogViewer());
|
||||
dockLog.addActionListener(event -> settings.setDockLogViewer(!settings.isDockLogViewer()));
|
||||
|
||||
Action syncAction = new AbstractAction(NLS.str("menu.sync"), ICON_SYNC) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@@ -1211,15 +1216,10 @@ public class MainWindow extends JFrame {
|
||||
deobfMenuItem = new JCheckBoxMenuItem(deobfAction);
|
||||
deobfMenuItem.setState(settings.isDeobfuscationOn());
|
||||
|
||||
Action logAction = new AbstractAction(NLS.str("menu.log"), ICON_LOG) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
LogViewerDialog.open(MainWindow.this);
|
||||
}
|
||||
};
|
||||
logAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.log"));
|
||||
logAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_L,
|
||||
UiUtils.ctrlButton() | KeyEvent.SHIFT_DOWN_MASK));
|
||||
ActionHandler showLog = new ActionHandler(ev -> showLogViewer(LogOptions.current()));
|
||||
showLog.setNameAndDesc(NLS.str("menu.log"));
|
||||
showLog.setIcon(ICON_LOG);
|
||||
showLog.setKeyBinding(getKeyStroke(KeyEvent.VK_L, UiUtils.ctrlButton() | KeyEvent.SHIFT_DOWN_MASK));
|
||||
|
||||
Action aboutAction = new AbstractAction(NLS.str("menu.about"), ICON_INFO) {
|
||||
@Override
|
||||
@@ -1296,6 +1296,7 @@ public class MainWindow extends JFrame {
|
||||
view.add(syncAction);
|
||||
view.add(heapUsageBarMenuItem);
|
||||
view.add(alwaysSelectOpened);
|
||||
view.add(dockLog);
|
||||
|
||||
JMenu nav = new JMenu(NLS.str("menu.navigation"));
|
||||
nav.setMnemonic(KeyEvent.VK_N);
|
||||
@@ -1319,7 +1320,7 @@ public class MainWindow extends JFrame {
|
||||
|
||||
JMenu help = new JMenu(NLS.str("menu.help"));
|
||||
help.setMnemonic(KeyEvent.VK_H);
|
||||
help.add(logAction);
|
||||
help.add(showLog);
|
||||
if (Jadx.isDevVersion()) {
|
||||
help.add(new AbstractAction("Show sample error report") {
|
||||
@Override
|
||||
@@ -1373,7 +1374,7 @@ public class MainWindow extends JFrame {
|
||||
toolbar.add(quarkAction);
|
||||
toolbar.add(openDeviceAction);
|
||||
toolbar.addSeparator();
|
||||
toolbar.add(logAction);
|
||||
toolbar.add(showLog);
|
||||
toolbar.addSeparator();
|
||||
toolbar.add(prefsAction);
|
||||
toolbar.addSeparator();
|
||||
@@ -1403,9 +1404,9 @@ public class MainWindow extends JFrame {
|
||||
private void initUI() {
|
||||
setMinimumSize(new Dimension(200, 150));
|
||||
mainPanel = new JPanel(new BorderLayout());
|
||||
splitPane = new JSplitPane();
|
||||
splitPane.setResizeWeight(SPLIT_PANE_RESIZE_WEIGHT);
|
||||
mainPanel.add(splitPane);
|
||||
treeSplitPane = new JSplitPane();
|
||||
treeSplitPane.setResizeWeight(SPLIT_PANE_RESIZE_WEIGHT);
|
||||
mainPanel.add(treeSplitPane);
|
||||
|
||||
DefaultMutableTreeNode treeRootNode = new DefaultMutableTreeNode(NLS.str("msg.open_file"));
|
||||
treeModel = new DefaultTreeModel(treeRootNode);
|
||||
@@ -1486,7 +1487,7 @@ public class MainWindow extends JFrame {
|
||||
});
|
||||
|
||||
progressPane = new ProgressPanel(this, true);
|
||||
IssuesPanel issuesPanel = new IssuesPanel(this);
|
||||
issuesPanel = new IssuesPanel(this);
|
||||
|
||||
JPanel leftPane = new JPanel(new BorderLayout());
|
||||
JScrollPane treeScrollPane = new JScrollPane(tree);
|
||||
@@ -1498,22 +1499,27 @@ public class MainWindow extends JFrame {
|
||||
|
||||
leftPane.add(treeScrollPane, BorderLayout.CENTER);
|
||||
leftPane.add(bottomPane, BorderLayout.PAGE_END);
|
||||
splitPane.setLeftComponent(leftPane);
|
||||
treeSplitPane.setLeftComponent(leftPane);
|
||||
|
||||
tabbedPane = new TabbedPane(this);
|
||||
tabbedPane.setMinimumSize(new Dimension(150, 150));
|
||||
splitPane.setRightComponent(tabbedPane);
|
||||
|
||||
rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
rightSplitPane.setTopComponent(tabbedPane);
|
||||
rightSplitPane.setResizeWeight(SPLIT_PANE_RESIZE_WEIGHT);
|
||||
|
||||
treeSplitPane.setRightComponent(rightSplitPane);
|
||||
|
||||
new DropTarget(this, DnDConstants.ACTION_COPY, new MainDropTarget(this));
|
||||
|
||||
heapUsageBar = new HeapUsageBar();
|
||||
mainPanel.add(heapUsageBar, BorderLayout.SOUTH);
|
||||
|
||||
verticalSplitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
verticalSplitter.setTopComponent(splitPane);
|
||||
verticalSplitter.setResizeWeight(SPLIT_PANE_RESIZE_WEIGHT);
|
||||
bottomSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
bottomSplitPane.setTopComponent(treeSplitPane);
|
||||
bottomSplitPane.setResizeWeight(SPLIT_PANE_RESIZE_WEIGHT);
|
||||
|
||||
mainPanel.add(verticalSplitter, BorderLayout.CENTER);
|
||||
mainPanel.add(bottomSplitPane, BorderLayout.CENTER);
|
||||
setContentPane(mainPanel);
|
||||
setTitle(DEFAULT_TITLE);
|
||||
}
|
||||
@@ -1643,6 +1649,9 @@ public class MainWindow extends JFrame {
|
||||
tree.setRowHeight(-1);
|
||||
|
||||
tabbedPane.loadSettings();
|
||||
if (logPanel != null) {
|
||||
logPanel.loadSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeWindow() {
|
||||
@@ -1650,7 +1659,7 @@ public class MainWindow extends JFrame {
|
||||
if (!ensureProjectIsSaved()) {
|
||||
return;
|
||||
}
|
||||
settings.setTreeWidth(splitPane.getDividerLocation());
|
||||
settings.setTreeWidth(treeSplitPane.getDividerLocation());
|
||||
settings.saveWindowPos(this);
|
||||
settings.setMainWindowExtendedState(getExtendedState());
|
||||
if (debuggerPanel != null) {
|
||||
@@ -1696,7 +1705,7 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
|
||||
private void saveSplittersInfo() {
|
||||
settings.setMainWindowVerticalSplitterLoc(verticalSplitter.getDividerLocation());
|
||||
settings.setMainWindowVerticalSplitterLoc(bottomSplitPane.getDividerLocation());
|
||||
settings.setDebuggerStackFrameSplitterLoc(debuggerPanel.getLeftSplitterLocation());
|
||||
settings.setDebuggerVarTreeSplitterLoc(debuggerPanel.getRightSplitterLocation());
|
||||
}
|
||||
@@ -1764,49 +1773,44 @@ public class MainWindow extends JFrame {
|
||||
if (debuggerPanel == null) {
|
||||
debuggerPanel = new JDebuggerPanel(this);
|
||||
debuggerPanel.loadSettings();
|
||||
verticalSplitter.setBottomComponent(debuggerPanel);
|
||||
bottomSplitPane.setBottomComponent(debuggerPanel);
|
||||
int loc = settings.getMainWindowVerticalSplitterLoc();
|
||||
if (loc == 0) {
|
||||
loc = 300;
|
||||
}
|
||||
verticalSplitter.setDividerLocation(loc);
|
||||
bottomSplitPane.setDividerLocation(loc);
|
||||
}
|
||||
}
|
||||
|
||||
private class RecentProjectsMenuListener implements MenuListener {
|
||||
private final JMenu menu;
|
||||
|
||||
public RecentProjectsMenuListener(JMenu menu) {
|
||||
this.menu = menu;
|
||||
public void showLogViewer(LogOptions logOptions) {
|
||||
if (settings.isDockLogViewer()) {
|
||||
showDockedLog(logOptions);
|
||||
} else {
|
||||
LogViewerDialog.open(this, logOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuSelected(MenuEvent menuEvent) {
|
||||
Set<Path> current = new HashSet<>(project.getFilePaths());
|
||||
List<JMenuItem> items = settings.getRecentProjects()
|
||||
.stream()
|
||||
.filter(path -> !current.contains(path))
|
||||
.map(path -> {
|
||||
JMenuItem menuItem = new JMenuItem(path.toAbsolutePath().toString());
|
||||
menuItem.addActionListener(e -> open(Collections.singletonList(path)));
|
||||
return menuItem;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
menu.removeAll();
|
||||
if (items.isEmpty()) {
|
||||
menu.add(new JMenuItem(NLS.str("menu.no_recent_projects")));
|
||||
} else {
|
||||
items.forEach(menu::add);
|
||||
}
|
||||
private void showDockedLog(LogOptions logOptions) {
|
||||
if (logPanel != null) {
|
||||
logPanel.applyLogOptions(logOptions);
|
||||
return;
|
||||
}
|
||||
Runnable undock = () -> {
|
||||
hideDockedLog();
|
||||
settings.setDockLogViewer(false);
|
||||
LogViewerDialog.open(this, logOptions);
|
||||
};
|
||||
logPanel = new LogPanel(this, logOptions, undock, this::hideDockedLog);
|
||||
rightSplitPane.setBottomComponent(logPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuDeselected(MenuEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuCanceled(MenuEvent e) {
|
||||
private void hideDockedLog() {
|
||||
if (logPanel == null) {
|
||||
return;
|
||||
}
|
||||
logPanel.dispose();
|
||||
logPanel = null;
|
||||
rightSplitPane.setBottomComponent(null);
|
||||
}
|
||||
|
||||
public JMenu getPluginsMenu() {
|
||||
|
||||
@@ -50,6 +50,7 @@ import ch.qos.logback.classic.Level;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.metadata.ICodeAnnotation;
|
||||
import jadx.api.metadata.annotations.NodeDeclareRef;
|
||||
import jadx.gui.logs.LogOptions;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.JResSearchNode;
|
||||
@@ -305,7 +306,7 @@ public abstract class CommonSearchDialog extends JFrame {
|
||||
progressInfoLabel.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
LogViewerDialog.openWithLevel(mainWindow, Level.INFO);
|
||||
mainWindow.showLogViewer(LogOptions.allWithLevel(Level.INFO));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,61 +5,53 @@ import java.awt.Container;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import jadx.gui.logs.LogOptions;
|
||||
import jadx.gui.logs.LogPanel;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.codearea.AbstractCodeArea;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
import jadx.gui.utils.logs.ILogListener;
|
||||
import jadx.gui.utils.logs.LogCollector;
|
||||
|
||||
public class LogViewerDialog extends JFrame {
|
||||
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 final transient JadxSettings settings;
|
||||
private transient RSyntaxTextArea textPane;
|
||||
private JComboBox<Level> levelCb;
|
||||
|
||||
private static LogViewerDialog openLogDialog;
|
||||
|
||||
public static void open(MainWindow mainWindow) {
|
||||
openWithLevel(mainWindow, level);
|
||||
}
|
||||
private final transient JadxSettings settings;
|
||||
private final transient LogPanel logPanel;
|
||||
|
||||
public static void openWithLevel(MainWindow mainWindow, Level newLevel) {
|
||||
level = newLevel;
|
||||
if (openLogDialog == null) {
|
||||
LogViewerDialog newLogDialog = new LogViewerDialog(mainWindow);
|
||||
newLogDialog.setVisible(true);
|
||||
openLogDialog = newLogDialog;
|
||||
public static void open(MainWindow mainWindow, LogOptions logOptions) {
|
||||
LogViewerDialog logDialog;
|
||||
if (openLogDialog != null) {
|
||||
logDialog = openLogDialog;
|
||||
} else {
|
||||
LogViewerDialog logDialog = openLogDialog;
|
||||
logDialog.levelCb.setSelectedItem(level);
|
||||
logDialog.setVisible(true);
|
||||
logDialog.toFront();
|
||||
logDialog = new LogViewerDialog(mainWindow, logOptions);
|
||||
openLogDialog = logDialog;
|
||||
}
|
||||
logDialog.setVisible(true);
|
||||
logDialog.toFront();
|
||||
}
|
||||
|
||||
private LogViewerDialog(MainWindow mainWindow) {
|
||||
this.settings = mainWindow.getSettings();
|
||||
initUI(mainWindow);
|
||||
registerLogListener();
|
||||
private LogViewerDialog(MainWindow mainWindow, LogOptions logOptions) {
|
||||
settings = mainWindow.getSettings();
|
||||
UiUtils.setWindowIcons(this);
|
||||
|
||||
Runnable dock = () -> {
|
||||
mainWindow.getSettings().setDockLogViewer(true);
|
||||
dispose();
|
||||
mainWindow.showLogViewer(LogOptions.current());
|
||||
};
|
||||
logPanel = new LogPanel(mainWindow, logOptions, dock, this::dispose);
|
||||
Container contentPane = getContentPane();
|
||||
contentPane.add(logPanel, BorderLayout.CENTER);
|
||||
|
||||
setTitle(NLS.str("log_viewer.title"));
|
||||
pack();
|
||||
setSize(800, 600);
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
setLocationRelativeTo(null);
|
||||
settings.loadWindowPos(this);
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
@@ -69,68 +61,9 @@ public class LogViewerDialog extends JFrame {
|
||||
});
|
||||
}
|
||||
|
||||
public final void initUI(MainWindow mainWindow) {
|
||||
UiUtils.setWindowIcons(this);
|
||||
|
||||
textPane = AbstractCodeArea.getDefaultArea(mainWindow);
|
||||
textPane.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
|
||||
|
||||
JPanel controlPane = new JPanel();
|
||||
controlPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
levelCb = new JComboBox<>(LEVEL_ITEMS);
|
||||
levelCb.setSelectedItem(level);
|
||||
levelCb.addActionListener(e -> {
|
||||
int i = levelCb.getSelectedIndex();
|
||||
level = LEVEL_ITEMS[i];
|
||||
registerLogListener();
|
||||
});
|
||||
JLabel levelLabel = new JLabel(NLS.str("log_viewer.log_level"));
|
||||
levelLabel.setLabelFor(levelCb);
|
||||
controlPane.add(levelLabel);
|
||||
controlPane.add(levelCb);
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(textPane);
|
||||
|
||||
JButton close = new JButton(NLS.str("tabs.close"));
|
||||
close.addActionListener(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(NLS.str("log_viewer.title"));
|
||||
pack();
|
||||
setSize(800, 600);
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
setLocationRelativeTo(null);
|
||||
}
|
||||
|
||||
private void registerLogListener() {
|
||||
LogCollector logCollector = LogCollector.getInstance();
|
||||
logCollector.resetListener();
|
||||
textPane.setText("");
|
||||
logCollector.registerListener(new ILogListener() {
|
||||
@Override
|
||||
public Level getFilterLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppend(final String logStr) {
|
||||
SwingUtilities.invokeLater(() -> textPane.append(logStr));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void close() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
LogCollector.getInstance().resetListener();
|
||||
logPanel.dispose();
|
||||
settings.saveWindowPos(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -9,15 +9,15 @@ import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import jadx.gui.logs.IssuesListener;
|
||||
import jadx.gui.logs.LogCollector;
|
||||
import jadx.gui.logs.LogOptions;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.dialog.LogViewerDialog;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
import jadx.gui.utils.logs.LogCollector;
|
||||
|
||||
public class IssuesPanel extends JPanel {
|
||||
private static final long serialVersionUID = -7720576036668459218L;
|
||||
@@ -26,15 +26,19 @@ public class IssuesPanel extends JPanel {
|
||||
private static final ImageIcon WARN_ICON = UiUtils.openSvgIcon("ui/warning");
|
||||
|
||||
private final MainWindow mainWindow;
|
||||
private final IssuesListener issuesListener;
|
||||
private JLabel errorLabel;
|
||||
private JLabel warnLabel;
|
||||
|
||||
public IssuesPanel(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
initUI();
|
||||
LogCollector.getInstance().registerIssueListener((error, warnings) -> {
|
||||
SwingUtilities.invokeLater(() -> onUpdate(error, warnings));
|
||||
});
|
||||
this.issuesListener = new IssuesListener(this);
|
||||
LogCollector.getInstance().registerListener(issuesListener);
|
||||
}
|
||||
|
||||
public int getErrorsCount() {
|
||||
return issuesListener.getErrors();
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
@@ -49,13 +53,13 @@ public class IssuesPanel extends JPanel {
|
||||
errorLabel.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
LogViewerDialog.openWithLevel(mainWindow, Level.ERROR);
|
||||
mainWindow.showLogViewer(LogOptions.allWithLevel(Level.ERROR));
|
||||
}
|
||||
});
|
||||
warnLabel.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
LogViewerDialog.openWithLevel(mainWindow, Level.WARN);
|
||||
mainWindow.showLogViewer(LogOptions.allWithLevel(Level.WARN));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -69,7 +73,7 @@ public class IssuesPanel extends JPanel {
|
||||
add(warnLabel);
|
||||
}
|
||||
|
||||
private void onUpdate(int error, int warnings) {
|
||||
public void onUpdate(int error, int warnings) {
|
||||
if (error == 0 && warnings == 0) {
|
||||
setVisible(false);
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package jadx.gui.ui.popupmenu;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.event.MenuEvent;
|
||||
import javax.swing.event.MenuListener;
|
||||
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class RecentProjectsMenuListener implements MenuListener {
|
||||
private final MainWindow mainWindow;
|
||||
private final JMenu menu;
|
||||
|
||||
public RecentProjectsMenuListener(MainWindow mainWindow, JMenu menu) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.menu = menu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuSelected(MenuEvent menuEvent) {
|
||||
Set<Path> current = new HashSet<>(mainWindow.getProject().getFilePaths());
|
||||
List<JMenuItem> items = mainWindow.getSettings().getRecentProjects()
|
||||
.stream()
|
||||
.filter(path -> !current.contains(path))
|
||||
.map(path -> {
|
||||
JMenuItem menuItem = new JMenuItem(path.toAbsolutePath().toString());
|
||||
menuItem.addActionListener(e -> mainWindow.open(Collections.singletonList(path)));
|
||||
return menuItem;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
menu.removeAll();
|
||||
if (items.isEmpty()) {
|
||||
menu.add(new JMenuItem(NLS.str("menu.no_recent_projects")));
|
||||
} else {
|
||||
items.forEach(menu::add);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuDeselected(MenuEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuCanceled(MenuEvent e) {
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package jadx.gui.utils.logs;
|
||||
|
||||
public interface ILogIssuesListener {
|
||||
void onChange(int error, int warnings);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package jadx.gui.utils.logs;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
public interface ILogListener {
|
||||
Level getFilterLevel();
|
||||
|
||||
void onAppend(String logStr);
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
package jadx.gui.utils.logs;
|
||||
|
||||
import java.util.Queue;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.AppenderBase;
|
||||
import ch.qos.logback.core.Layout;
|
||||
|
||||
public class LogCollector extends AppenderBase<ILoggingEvent> {
|
||||
public static final int BUFFER_SIZE = 5000;
|
||||
|
||||
private static final 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);
|
||||
}
|
||||
|
||||
private Layout<ILoggingEvent> layout;
|
||||
|
||||
@Nullable
|
||||
private ILogListener listener;
|
||||
@Nullable
|
||||
private ILogIssuesListener issuesListener;
|
||||
private int errors = 0;
|
||||
private int warnings = 0;
|
||||
|
||||
private final Queue<LogEvent> buffer = new LimitedQueue<>(BUFFER_SIZE);
|
||||
|
||||
public LogCollector() {
|
||||
setName("LogCollector");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(ILoggingEvent event) {
|
||||
synchronized (this) {
|
||||
Level level = event.getLevel();
|
||||
String msg = layout.doLayout(event);
|
||||
store(level, msg);
|
||||
if (listener != null && level.isGreaterOrEqual(listener.getFilterLevel())) {
|
||||
listener.onAppend(msg);
|
||||
}
|
||||
if (level == Level.ERROR) {
|
||||
errors++;
|
||||
issuesUpdated();
|
||||
} else if (level == Level.WARN) {
|
||||
warnings++;
|
||||
issuesUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void issuesUpdated() {
|
||||
if (issuesListener != null) {
|
||||
issuesListener.onChange(errors, warnings);
|
||||
}
|
||||
}
|
||||
|
||||
private void store(Level level, String msg) {
|
||||
buffer.offer(new LogEvent(level, msg));
|
||||
}
|
||||
|
||||
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 registerIssueListener(@NotNull ILogIssuesListener listener) {
|
||||
this.issuesListener = listener;
|
||||
synchronized (this) {
|
||||
listener.onChange(errors, warnings);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetListener() {
|
||||
this.listener = null;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
buffer.clear();
|
||||
errors = 0;
|
||||
warnings = 0;
|
||||
issuesUpdated();
|
||||
}
|
||||
|
||||
public int getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public int getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
private String init(Level filterLevel) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (LogEvent event : buffer) {
|
||||
if (event.getLevel().isGreaterOrEqual(filterLevel)) {
|
||||
sb.append(event.getMsg());
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package jadx.gui.utils.logs;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
final class LogEvent {
|
||||
private final Level level;
|
||||
private final String msg;
|
||||
|
||||
LogEvent(Level level, String msg) {
|
||||
this.level = level;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return level + ": " + msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package jadx.gui.utils.rx;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.BackpressureStrategy;
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.FlowableEmitter;
|
||||
import io.reactivex.FlowableOnSubscribe;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
public class DebounceUpdate {
|
||||
|
||||
private FlowableEmitter<Boolean> emitter;
|
||||
private final Disposable disposable;
|
||||
|
||||
public DebounceUpdate(int timeMs, Runnable action) {
|
||||
FlowableOnSubscribe<Boolean> source = emitter -> this.emitter = emitter;
|
||||
disposable = Flowable.create(source, BackpressureStrategy.LATEST)
|
||||
.debounce(timeMs, TimeUnit.MILLISECONDS)
|
||||
.subscribe(v -> action.run());
|
||||
}
|
||||
|
||||
public void requestUpdate() {
|
||||
emitter.onNext(Boolean.TRUE);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ menu.sync=Mit Editor synchronisieren
|
||||
menu.flatten=Codepaket erweitern
|
||||
menu.heapUsageBar=Speicherverbrauchsleiste anzeigen
|
||||
menu.alwaysSelectOpened=Immer geöffnete Datei/Klasse auswählen
|
||||
#menu.dock_log=Dock log viewer
|
||||
menu.navigation=Navigation
|
||||
menu.text_search=Textsuche
|
||||
menu.class_search=Klassen-Suche
|
||||
@@ -143,6 +144,12 @@ comment_dialog.usage=Shift + Enter verwenden, um eine neue Zeile zu beginnen
|
||||
|
||||
log_viewer.title=Log-Anzeige
|
||||
log_viewer.log_level=Log-Level:
|
||||
#log_viewer.mode=Mode:
|
||||
#log_viewer.modes=All|All scripts|Current script
|
||||
#log_viewer.hide=Hide
|
||||
#log_viewer.dock=Dock
|
||||
#log_viewer.undock=Undock
|
||||
#log_viewer.clear=Clear
|
||||
|
||||
about_dialog.title=Über JADX
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ menu.sync=Sync with editor
|
||||
menu.flatten=Show flatten packages
|
||||
menu.heapUsageBar=Show memory usage bar
|
||||
menu.alwaysSelectOpened=Always Select Opened File/Class
|
||||
menu.dock_log=Dock log viewer
|
||||
menu.navigation=Navigation
|
||||
menu.text_search=Text search
|
||||
menu.class_search=Class search
|
||||
@@ -143,6 +144,12 @@ comment_dialog.usage=Use Shift + Enter for start a new line
|
||||
|
||||
log_viewer.title=Log Viewer
|
||||
log_viewer.log_level=Log level:
|
||||
log_viewer.mode=Mode:
|
||||
log_viewer.modes=All|All scripts|Current script
|
||||
log_viewer.hide=Hide
|
||||
log_viewer.dock=Dock
|
||||
log_viewer.undock=Undock
|
||||
log_viewer.clear=Clear
|
||||
|
||||
about_dialog.title=About JADX
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ menu.sync=Sincronizar con el editor
|
||||
menu.flatten=Mostrar paquetes en vista plana
|
||||
#menu.heapUsageBar=
|
||||
#menu.alwaysSelectOpened=Always Select Opened File/Class
|
||||
#menu.dock_log=Dock log viewer
|
||||
menu.navigation=Navegación
|
||||
menu.text_search=Buscar texto
|
||||
menu.class_search=Buscar clase
|
||||
@@ -143,6 +144,12 @@ usage_dialog.label=Usage for:
|
||||
|
||||
log_viewer.title=Visor log
|
||||
log_viewer.log_level=Nivel log:
|
||||
#log_viewer.mode=Mode:
|
||||
#log_viewer.modes=All|All scripts|Current script
|
||||
#log_viewer.hide=Hide
|
||||
#log_viewer.dock=Dock
|
||||
#log_viewer.undock=Undock
|
||||
#log_viewer.clear=Clear
|
||||
|
||||
about_dialog.title=Sobre JADX
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ menu.sync=에디터와 동기화
|
||||
menu.flatten=플랫 패키지 표시
|
||||
menu.heapUsageBar=메모리 사용량 표시
|
||||
menu.alwaysSelectOpened=항상 열린 파일/클래스 선택
|
||||
#menu.dock_log=Dock log viewer
|
||||
menu.navigation=네비게이션
|
||||
menu.text_search=텍스트 검색
|
||||
menu.class_search=클래스 검색
|
||||
@@ -143,6 +144,12 @@ comment_dialog.usage=Shift + Enter 를 입력해 새 라인에 입력
|
||||
|
||||
log_viewer.title=로그 뷰어
|
||||
log_viewer.log_level=로그 레벨:
|
||||
#log_viewer.mode=Mode:
|
||||
#log_viewer.modes=All|All scripts|Current script
|
||||
#log_viewer.hide=Hide
|
||||
#log_viewer.dock=Dock
|
||||
#log_viewer.undock=Undock
|
||||
#log_viewer.clear=Clear
|
||||
|
||||
about_dialog.title=JADX 정보
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ menu.sync=Sincronizar com editor
|
||||
menu.flatten=Mostrar pacotes achatados
|
||||
menu.heapUsageBar=Mostrar uso de memória
|
||||
menu.alwaysSelectOpened=Sempre selecionar arquivo/classe aberta
|
||||
#menu.dock_log=Dock log viewer
|
||||
menu.navigation=Navegação
|
||||
menu.text_search=Buscar por texto
|
||||
menu.class_search=Buscar por classe
|
||||
@@ -143,6 +144,12 @@ comment_dialog.usage=Use Shift + Enter para pular uma linha
|
||||
|
||||
log_viewer.title=Visualizador de log
|
||||
log_viewer.log_level=Nível do log:
|
||||
#log_viewer.mode=Mode:
|
||||
#log_viewer.modes=All|All scripts|Current script
|
||||
#log_viewer.hide=Hide
|
||||
#log_viewer.dock=Dock
|
||||
#log_viewer.undock=Undock
|
||||
#log_viewer.clear=Clear
|
||||
|
||||
about_dialog.title=Sobre o JADX
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ menu.sync=与编辑器同步
|
||||
menu.flatten=展开显示代码包
|
||||
menu.heapUsageBar=显示内存使用栏
|
||||
menu.alwaysSelectOpened=始终选中打开的文件/类
|
||||
#menu.dock_log=Dock log viewer
|
||||
menu.navigation=导航
|
||||
menu.text_search=文本搜索
|
||||
menu.class_search=类名搜索
|
||||
@@ -143,6 +144,12 @@ comment_dialog.usage=使用 Shift + Enter 换行
|
||||
|
||||
log_viewer.title=日志查看器
|
||||
log_viewer.log_level=日志等级:
|
||||
#log_viewer.mode=Mode:
|
||||
#log_viewer.modes=All|All scripts|Current script
|
||||
#log_viewer.hide=Hide
|
||||
#log_viewer.dock=Dock
|
||||
#log_viewer.undock=Undock
|
||||
#log_viewer.clear=Clear
|
||||
|
||||
about_dialog.title=关于 JADX
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ menu.sync=與編輯器同步
|
||||
menu.flatten=展開顯示套件
|
||||
menu.heapUsageBar=顯示記憶體使用率條
|
||||
menu.alwaysSelectOpened=總是選擇已開啟的檔案/類別
|
||||
#menu.dock_log=Dock log viewer
|
||||
menu.navigation=瀏覽
|
||||
menu.text_search=文字搜尋
|
||||
menu.class_search=類別搜尋
|
||||
@@ -143,6 +144,12 @@ comment_dialog.usage=按下 Shift + Enter 來換行
|
||||
|
||||
log_viewer.title=日誌檢視器
|
||||
log_viewer.log_level=紀錄層級:
|
||||
#log_viewer.mode=Mode:
|
||||
#log_viewer.modes=All|All scripts|Current script
|
||||
#log_viewer.hide=Hide
|
||||
#log_viewer.dock=Dock
|
||||
#log_viewer.undock=Undock
|
||||
#log_viewer.clear=Clear
|
||||
|
||||
about_dialog.title=關於 JADX
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ fun generateFieldSnippet(fld: FieldNode): String {
|
||||
return """
|
||||
${generateClassSnippet(fld.parentClass)}
|
||||
${fld.name} = ${fld.parentClass.name}.$rawFieldName.value;
|
||||
""".trimIndent()
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
fun isOverloaded(methodNode: MethodNode): Boolean {
|
||||
|
||||
+3
-1
@@ -28,6 +28,8 @@ import kotlin.script.experimental.jvm.JvmDependency
|
||||
import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
|
||||
const val JADX_SCRIPT_LOG_PREFIX = "JadxScript:"
|
||||
|
||||
@KotlinScript(
|
||||
fileExtension = "jadx.kts",
|
||||
compilationConfiguration = JadxScriptConfiguration::class
|
||||
@@ -36,7 +38,7 @@ abstract class JadxScriptTemplate(
|
||||
private val scriptData: JadxScriptData
|
||||
) {
|
||||
val scriptName = scriptData.scriptName
|
||||
val log = KotlinLogging.logger("JadxScript:$scriptName")
|
||||
val log = KotlinLogging.logger("$JADX_SCRIPT_LOG_PREFIX$scriptName")
|
||||
|
||||
fun getJadxInstance() = JadxScriptInstance(scriptData, log)
|
||||
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ class JadxScriptData(
|
||||
) {
|
||||
val afterLoad: MutableList<() -> Unit> = ArrayList()
|
||||
|
||||
val scriptName get() = scriptFile.name.removeSuffix(".jadx.kts")
|
||||
val scriptName = scriptFile.name.removeSuffix(".jadx.kts")
|
||||
}
|
||||
|
||||
class JadxScriptInstance(
|
||||
|
||||
Reference in New Issue
Block a user