diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index 73eeda752..e445db64b 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -3,10 +3,13 @@ package jadx.gui.settings; import jadx.cli.JadxCLIArgs; import java.awt.Font; +import java.awt.Window; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; @@ -31,6 +34,8 @@ public class JadxSettings extends JadxCLIArgs { private boolean useFastSearch = false; private boolean autoStartJobs = true; + private Map windowPos = new HashMap(); + public JadxSettings() { setSkipResources(true); } @@ -89,6 +94,25 @@ public class JadxSettings extends JadxCLIArgs { sync(); } + public void saveWindowPos(Window window) { + WindowLocation pos = new WindowLocation(window.getClass().getSimpleName(), + window.getX(), window.getY(), + window.getWidth(), window.getHeight() + ); + windowPos.put(pos.getWindowId(), pos); + sync(); + } + + public boolean loadWindowPos(Window window) { + WindowLocation pos = windowPos.get(window.getClass().getSimpleName()); + if (pos == null) { + return false; + } + window.setLocation(pos.getX(), pos.getY()); + window.setSize(pos.getWidth(), pos.getHeight()); + return true; + } + public void setThreadsCount(int threadsCount) { this.threadsCount = threadsCount; } diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java index 001d0bd9a..2fef752e1 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java @@ -12,6 +12,7 @@ import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.SwingConstants; @@ -52,6 +53,13 @@ public class JadxSettingsWindow extends JDialog { this.startSettings = JadxSettingsAdapter.makeString(settings); initUI(); + + setTitle(NLS.str("preferences.title")); + setSize(400, 550); + setLocationRelativeTo(null); + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + setModalityType(ModalityType.APPLICATION_MODAL); + pack(); } private void initUI() { @@ -79,9 +87,29 @@ public class JadxSettingsWindow extends JDialog { } }); + JButton resetBtn = new JButton(NLS.str("preferences.reset")); + resetBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + int res = JOptionPane.showConfirmDialog( + JadxSettingsWindow.this, + NLS.str("preferences.reset_message"), + NLS.str("preferences.reset_title"), + JOptionPane.YES_NO_OPTION); + if (res == JOptionPane.YES_OPTION) { + String defaults = JadxSettingsAdapter.makeString(new JadxSettings()); + JadxSettingsAdapter.fill(settings, defaults); + getContentPane().removeAll(); + initUI(); + pack(); + repaint(); + } + } + }); + JPanel buttonPane = new JPanel(); buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + buttonPane.add(resetBtn); buttonPane.add(Box.createHorizontalGlue()); buttonPane.add(saveBtn); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); @@ -91,13 +119,6 @@ public class JadxSettingsWindow extends JDialog { contentPane.add(panel, BorderLayout.CENTER); contentPane.add(buttonPane, BorderLayout.PAGE_END); getRootPane().setDefaultButton(saveBtn); - - setTitle(NLS.str("preferences.title")); - setSize(400, 550); - setLocationRelativeTo(null); - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - setModalityType(ModalityType.APPLICATION_MODAL); - pack(); } private SettingsGroup makeDeobfuscationGroup() { diff --git a/jadx-gui/src/main/java/jadx/gui/settings/WindowLocation.java b/jadx-gui/src/main/java/jadx/gui/settings/WindowLocation.java new file mode 100644 index 000000000..53f5abc13 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/settings/WindowLocation.java @@ -0,0 +1,50 @@ +package jadx.gui.settings; + +public class WindowLocation { + + private final String windowId; + + private final int x; + private final int y; + private final int width; + private final int height; + + public WindowLocation(String windowId, int x, int y, int width, int height) { + this.windowId = windowId; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public String getWindowId() { + return windowId; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + @Override + public String toString() { + return "WindowLocation{" + + "id='" + windowId + '\'' + + ", x=" + x + + ", y=" + y + + ", width=" + width + + ", height=" + height + + '}'; + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java index 194dc6a1c..12f702fda 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java @@ -1,6 +1,7 @@ package jadx.gui.ui; import jadx.gui.jobs.BackgroundJob; +import jadx.gui.jobs.BackgroundWorker; import jadx.gui.jobs.DecompileJob; import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.TextNode; @@ -78,6 +79,10 @@ public abstract class CommonSearchDialog extends JDialog { this.codeFont = mainWindow.getSettings().getFont(); } + public void loadWindowPos() { + mainWindow.getSettings().loadWindowPos(this); + } + public void prepare() { if (cache.getIndexJob().isComplete()) { loadFinishedCommon(); @@ -100,6 +105,12 @@ public abstract class CommonSearchDialog extends JDialog { dispose(); } + @Override + public void dispose() { + mainWindow.getSettings().saveWindowPos(this); + super.dispose(); + } + protected void initCommon() { KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); getRootPane().registerKeyboardAction(new ActionListener() { @@ -348,7 +359,11 @@ public abstract class CommonSearchDialog extends JDialog { @Override public Void doInBackground() { try { - mainWindow.getBackgroundWorker().exec(); + BackgroundWorker backgroundWorker = mainWindow.getBackgroundWorker(); + if (backgroundWorker == null) { + return null; + } + backgroundWorker.exec(); DecompileJob decompileJob = cache.getDecompileJob(); progressPane.changeLabel(this, decompileJob.getInfoString()); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java b/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java index 04346086e..68033e227 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java @@ -1,6 +1,7 @@ package jadx.gui.ui; import ch.qos.logback.classic.Level; +import jadx.gui.settings.JadxSettings; import jadx.gui.utils.LogCollector; import jadx.gui.utils.NLS; @@ -24,11 +25,14 @@ class LogViewer extends JDialog { private static final Level[] LEVEL_ITEMS = {Level.DEBUG, Level.INFO, Level.WARN, Level.ERROR}; private static Level level = Level.WARN; + private final JadxSettings settings; private RSyntaxTextArea textPane; - public LogViewer() { + public LogViewer(JadxSettings settings) { + this.settings = settings; initUI(); registerLogListener(); + settings.loadWindowPos(this); } public final void initUI() { @@ -98,11 +102,13 @@ class LogViewer extends JDialog { } private void close() { - LogCollector.getInstance().resetListener(); dispose(); } - public static void main(String[] args) { - new LogViewer().setVisible(true); + @Override + public void dispose() { + LogCollector.getInstance().resetListener(); + settings.saveWindowPos(this); + super.dispose(); } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index fec78a77c..2e41bd6e0 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -397,7 +397,7 @@ public class MainWindow extends JFrame { Action logAction = new AbstractAction(NLS.str("menu.log"), ICON_LOG) { @Override public void actionPerformed(ActionEvent e) { - new LogViewer().setVisible(true); + new LogViewer(settings).setVisible(true); } }; logAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("menu.log")); @@ -593,6 +593,9 @@ public class MainWindow extends JFrame { } public void setLocationAndPosition() { + if (this.settings.loadWindowPos(this)) { + return; + } GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); DisplayMode mode = gd.getDisplayMode(); int w = mode.getWidth(); @@ -608,6 +611,7 @@ public class MainWindow extends JFrame { @Override public void dispose() { + settings.saveWindowPos(this); cancelBackgroundJobs(); super.dispose(); } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java index 6ba405b78..00ddba472 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java @@ -64,6 +64,7 @@ public class SearchDialog extends CommonSearchDialog { }); } }); + loadWindowPos(); } protected void openInit() { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/UsageDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/UsageDialog.java index a558b7cb5..7a05d25d0 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/UsageDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/UsageDialog.java @@ -43,6 +43,7 @@ public class UsageDialog extends CommonSearchDialog { }); } }); + loadWindowPos(); } protected void openInit() { diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index dcb59db5a..dee8c19b9 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -71,6 +71,9 @@ preferences.deobfuscation_max_len=Maximum name length preferences.deobfuscation_source_alias=Use source file name as class name alias preferences.save=Save preferences.cancel=Cancel +preferences.reset=Reset +preferences.reset_message=Reset settings to default values? +preferences.reset_title=Reset settings msg.open_file=Please open file msg.saving_sources=Saving sources