fix(gui): redirect plugins menu action to show plugins settings page

This commit is contained in:
Skylot
2025-06-01 18:55:11 +01:00
parent e51a7fe417
commit b82791706a
12 changed files with 106 additions and 19 deletions
@@ -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<ISettingsGroup> 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) {
@@ -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<ISettingsGroup> groups) {
public SettingsTree(JadxSettingsWindow settingsWindow) {
this.settingsWindow = settingsWindow;
}
public void init(List<ISettingsGroup> 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<TreeNode> 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) {
@@ -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) {
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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=Удалить
@@ -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=卸载
@@ -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=解除安裝