From b82791706ad4aa951543f8c6c1cf01f2e92dba18 Mon Sep 17 00:00:00 2001 From: Skylot <118523+skylot@users.noreply.github.com> Date: Sun, 1 Jun 2025 18:55:11 +0100 Subject: [PATCH] fix(gui): redirect plugins menu action to show plugins settings page --- .../gui/settings/ui/JadxSettingsWindow.java | 50 +++++++++++++++++-- .../jadx/gui/settings/ui/SettingsTree.java | 47 +++++++++++++---- .../src/main/java/jadx/gui/ui/MainWindow.java | 19 ++++--- .../resources/i18n/Messages_de_DE.properties | 1 + .../resources/i18n/Messages_en_US.properties | 1 + .../resources/i18n/Messages_es_ES.properties | 1 + .../resources/i18n/Messages_id_ID.properties | 1 + .../resources/i18n/Messages_ko_KR.properties | 1 + .../resources/i18n/Messages_pt_BR.properties | 1 + .../resources/i18n/Messages_ru_RU.properties | 1 + .../resources/i18n/Messages_zh_CN.properties | 1 + .../resources/i18n/Messages_zh_TW.properties | 1 + 12 files changed, 106 insertions(+), 19 deletions(-) diff --git a/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java b/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java index 157526484..c5ea930be 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java @@ -38,6 +38,7 @@ import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +57,8 @@ import jadx.api.plugins.events.JadxEvents; import jadx.api.plugins.events.types.ReloadSettingsWindow; import jadx.api.plugins.gui.ISettingsGroup; import jadx.core.utils.GsonUtils; +import jadx.core.utils.StringUtils; +import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.settings.JadxSettings; import jadx.gui.settings.JadxSettingsAdapter; import jadx.gui.settings.JadxUpdateChannel; @@ -91,6 +94,7 @@ public class JadxSettingsWindow extends JDialog { private transient boolean needReload = false; private transient SettingsTree tree; private List groups; + private JPanel wrapGroupPanel; public JadxSettingsWindow(MainWindow mainWindow, JadxSettings settings) { this.mainWindow = mainWindow; @@ -127,7 +131,7 @@ public class JadxSettingsWindow extends JDialog { } private void initUI() { - JPanel wrapGroupPanel = new JPanel(new BorderLayout(10, 10)); + wrapGroupPanel = new JPanel(new BorderLayout(10, 10)); groups = new ArrayList<>(); groups.add(makeDecompilationGroup()); @@ -140,8 +144,8 @@ public class JadxSettingsWindow extends JDialog { groups.add(new PluginSettings(mainWindow, settings).build()); groups.add(makeOtherGroup()); - tree = new SettingsTree(); - tree.init(wrapGroupPanel, groups); + tree = new SettingsTree(this); + tree.init(groups); tree.setFocusable(true); JScrollPane leftPane = new JScrollPane(tree); leftPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 3, 3)); @@ -194,6 +198,46 @@ public class JadxSettingsWindow extends JDialog { return buttonPane; } + /** + * Activate the settings page by location. + * + * @param location - can be title of a settings group or settings group class implementation (end + * with .class) + */ + public void activatePage(String location) { + if (location.endsWith(".class")) { + String clsName = StringUtils.removeSuffix(location, ".class"); + for (ISettingsGroup group : groups) { + String groupCls = group.getClass().getSimpleName(); + if (groupCls.equals(clsName)) { + selectGroup(group); + return; + } + } + throw new JadxRuntimeException("No setting group class: " + location); + } else { + for (ISettingsGroup group : groups) { + if (group.getTitle().equals(location)) { + selectGroup(group); + return; + } + } + throw new JadxRuntimeException("No setting group with title: " + location); + } + } + + public void selectGroup(ISettingsGroup group) { + tree.selectGroup(group); + } + + public void activateGroup(@Nullable ISettingsGroup group) { + wrapGroupPanel.removeAll(); + if (group != null) { + wrapGroupPanel.add(group.buildComponent()); + } + wrapGroupPanel.updateUI(); + } + private static void enableComponents(Container container, boolean enable) { for (Component component : container.getComponents()) { if (component instanceof Container) { diff --git a/jadx-gui/src/main/java/jadx/gui/settings/ui/SettingsTree.java b/jadx-gui/src/main/java/jadx/gui/settings/ui/SettingsTree.java index ccfe48cdd..1d8a12fa9 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/ui/SettingsTree.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/ui/SettingsTree.java @@ -1,10 +1,10 @@ package jadx.gui.settings.ui; import java.util.Collections; +import java.util.Enumeration; import java.util.List; import java.util.Objects; -import javax.swing.JPanel; import javax.swing.JTree; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeWillExpandListener; @@ -15,18 +15,26 @@ import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; +import org.jetbrains.annotations.Nullable; + import jadx.api.plugins.gui.ISettingsGroup; +import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.utils.NLS; public class SettingsTree extends JTree { + private final JadxSettingsWindow settingsWindow; - public void init(JPanel groupPanel, List groups) { + public SettingsTree(JadxSettingsWindow settingsWindow) { + this.settingsWindow = settingsWindow; + } + + public void init(List groups) { DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode(NLS.str("preferences.title")); addGroups(treeRoot, groups); setModel(new DefaultTreeModel(treeRoot)); getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); setFocusable(false); - addTreeSelectionListener(e -> switchGroup(groupPanel)); + addTreeSelectionListener(ev -> switchGroup()); // expand all nodes and disallow collapsing setNodeExpandedState(this, treeRoot, true); addTreeWillExpandListener(new DisableRootCollapseListener(treeRoot)); @@ -41,13 +49,34 @@ public class SettingsTree extends JTree { } } - private void switchGroup(JPanel groupPanel) { - Object selected = getLastSelectedPathComponent(); - groupPanel.removeAll(); - if (selected instanceof SettingsTreeNode) { - groupPanel.add(((SettingsTreeNode) selected).getGroup().buildComponent()); + public void selectGroup(ISettingsGroup group) { + SettingsTreeNode node = searchTreeNode(group); + if (node == null) { + throw new JadxRuntimeException("Settings group not found: " + group); + } + setSelectionPath(new TreePath(node.getPath())); + } + + private @Nullable SettingsTreeNode searchTreeNode(ISettingsGroup group) { + DefaultMutableTreeNode root = (DefaultMutableTreeNode) getModel().getRoot(); + Enumeration enumeration = root.children(); + while (enumeration.hasMoreElements()) { + SettingsTreeNode node = (SettingsTreeNode) enumeration.nextElement(); + if (node.getGroup() == group) { + return node; + } + } + return null; + } + + private void switchGroup() { + Object selected = getLastSelectedPathComponent(); + if (selected instanceof SettingsTreeNode) { + ISettingsGroup group = ((SettingsTreeNode) selected).getGroup(); + settingsWindow.activateGroup(group); + } else { + settingsWindow.activateGroup(null); } - groupPanel.updateUI(); } private static void setNodeExpandedState(JTree tree, TreeNode node, boolean expanded) { 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 8a3693788..7353001e0 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -39,7 +39,6 @@ import javax.swing.Action; import javax.swing.Box; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; -import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; @@ -117,7 +116,6 @@ import jadx.gui.plugins.quark.QuarkDialog; import jadx.gui.settings.JadxProject; import jadx.gui.settings.JadxSettings; import jadx.gui.settings.ui.JadxSettingsWindow; -import jadx.gui.settings.ui.plugins.PluginSettings; import jadx.gui.tree.TreeExpansionService; import jadx.gui.treemodel.ApkSignatureNode; import jadx.gui.treemodel.JInputFiles; @@ -1138,7 +1136,7 @@ public class MainWindow extends JFrame { hexViewerMenu = new JadxMenu(NLS.str("menu.hex_viewer"), shortcutsController); initHexViewMenu(); - JadxGuiAction prefsAction = new JadxGuiAction(ActionModel.PREFS, this::openSettings); + JadxGuiAction prefsAction = new JadxGuiAction(ActionModel.PREFS, () -> openSettings()); JadxGuiAction exitAction = new JadxGuiAction(ActionModel.EXIT, this::closeWindow); isFlattenPackage = settings.isFlattenPackage(); @@ -1532,16 +1530,23 @@ public class MainWindow extends JFrame { } private void openSettings() { + openSettings(null); + } + + private void openSettings(@Nullable String navigateTo) { settingsOpen = true; - JDialog settingsWindow = new JadxSettingsWindow(MainWindow.this, settings); - settingsWindow.setVisible(true); + JadxSettingsWindow settingsWindow = new JadxSettingsWindow(MainWindow.this, settings); settingsWindow.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { settingsOpen = false; } }); + if (navigateTo != null) { + settingsWindow.activatePage(navigateTo); + } + settingsWindow.setVisible(true); } public boolean isSettingsOpen() { @@ -1780,8 +1785,8 @@ public class MainWindow extends JFrame { public void resetPluginsMenu() { pluginsMenu.removeAll(); - pluginsMenu.add(new ActionHandler(() -> new PluginSettings(this, settings).addPlugin()) - .withNameAndDesc(NLS.str("preferences.plugins.install"))); + pluginsMenu.add(new ActionHandler(() -> openSettings("PluginSettingsGroup.class")) + .withNameAndDesc(NLS.str("preferences.plugins.manage"))); } public void addToPluginsMenu(Action item) { diff --git a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties index 7e59ef475..228ac009f 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=Ressourcendatei-Erweiterungen ('xml|html', * für alle) preferences.res_skip_file=Ressourcendateien überspringen, wenn sie größer sind (MB) (0 - ausschalten) preferences.tab_dnd_appearance=Erscheinungsbild der Registerkarte "Verschieben" +#preferences.plugins.manage=Manage plugins preferences.plugins.install=Plugin installieren preferences.plugins.install_btn=Installieren preferences.plugins.uninstall_btn=Deinstallieren 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 1b976f441..d753ae9d7 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=Resource files extensions ('xml|html', * for all) preferences.res_skip_file=Skip resources files if larger (MB) (0 - disable) preferences.tab_dnd_appearance=Dragging tab appearance +preferences.plugins.manage=Manage plugins preferences.plugins.install=Install plugin preferences.plugins.install_btn=Install preferences.plugins.uninstall_btn=Uninstall diff --git a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties index 87e6791f9..b7b9eb3b3 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -302,6 +302,7 @@ preferences.rename_use_source_name_as_class_name_alias=Usar el nombre del source #preferences.res_skip_file=Skip resources files if larger (MB) (0 - disable) #preferences.tab_dnd_appearance=Dragging tab appearance +#preferences.plugins.manage=Manage plugins #preferences.plugins.install=Install plugin #preferences.plugins.install_btn=Install #preferences.plugins.uninstall_btn=Uninstall diff --git a/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties b/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties index 52a579aba..5740c1d09 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=Ekstensi berkas sumber daya ('xml|html', * untuk semua) preferences.res_skip_file=Lewati berkas sumber daya jika lebih besar (MB) (0 - nonaktifkan) preferences.tab_dnd_appearance=Dragging tab appearance +#preferences.plugins.manage=Manage plugins preferences.plugins.install=Instal plugin preferences.plugins.install_btn=Instal preferences.plugins.uninstall_btn=Uninstal diff --git a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties index 8417b9adc..90fd3358c 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=파일 확장자 (예: .xml|.html) (* 은 전체를 의 preferences.res_skip_file=이 옵션보다 큰 파일 건너 뛰기 (MB) preferences.tab_dnd_appearance=Dragging tab appearance +#preferences.plugins.manage=Manage plugins #preferences.plugins.install=Install plugin #preferences.plugins.install_btn=Install #preferences.plugins.uninstall_btn=Uninstall diff --git a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties index aa357fd34..15e2ca1b9 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=Extensões de arquivos (ex: .xml|.html), * significa to preferences.res_skip_file=Pular arquivos excedidos preferences.tab_dnd_appearance=Dragging tab appearance +#preferences.plugins.manage=Manage plugins #preferences.plugins.install=Install plugin #preferences.plugins.install_btn=Install #preferences.plugins.uninstall_btn=Uninstall diff --git a/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties b/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties index b48bf45ca..3e96bd9fb 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=Расширения файлов ресурсов ('xm preferences.res_skip_file=Пропускать ресурсы больше чем (в МБ) preferences.tab_dnd_appearance=Dragging tab appearance +#preferences.plugins.manage=Manage plugins preferences.plugins.install=Установить плагин preferences.plugins.install_btn=Установить preferences.plugins.uninstall_btn=Удалить diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index c8d4aa824..fdbe3b46d 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=文件扩展名(比如 .xml|.html),* 表示所有 preferences.res_skip_file=跳过文件大小(MB) preferences.tab_dnd_appearance=拖拽选项卡外观 +#preferences.plugins.manage=Manage plugins preferences.plugins.install=安装插件 preferences.plugins.install_btn=安装 preferences.plugins.uninstall_btn=卸载 diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties index 38cde4125..8717290f7 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties @@ -302,6 +302,7 @@ preferences.res_file_ext=副檔名 (e.g. .xml|.html), * 表示全部 preferences.res_skip_file=略過大於此值的檔案 (MB) preferences.tab_dnd_appearance=拖動分頁時外觀 +#preferences.plugins.manage=Manage plugins preferences.plugins.install=安裝外掛程式 preferences.plugins.install_btn=安裝 preferences.plugins.uninstall_btn=解除安裝