From ee2556ecb6e4eda433ed31cd95d2a793f2c816f1 Mon Sep 17 00:00:00 2001 From: Skylot Date: Thu, 20 Apr 2023 22:00:06 +0100 Subject: [PATCH] fix(gui): update mappings node instead full reload on 'save as' (#1732) --- .../plugins/mappings/RenameMappingsGui.java | 36 +++++++++++++++++-- .../gui/settings/TabStateViewAdapter.java | 2 +- .../main/java/jadx/gui/treemodel/JInputs.java | 7 ---- .../main/java/jadx/gui/treemodel/JNode.java | 17 ++++++++- .../src/main/java/jadx/gui/ui/MainWindow.java | 7 ++++ 5 files changed, 58 insertions(+), 11 deletions(-) diff --git a/jadx-gui/src/main/java/jadx/gui/plugins/mappings/RenameMappingsGui.java b/jadx-gui/src/main/java/jadx/gui/plugins/mappings/RenameMappingsGui.java index 8057507ce..5ed93b155 100644 --- a/jadx-gui/src/main/java/jadx/gui/plugins/mappings/RenameMappingsGui.java +++ b/jadx-gui/src/main/java/jadx/gui/plugins/mappings/RenameMappingsGui.java @@ -27,9 +27,13 @@ import jadx.core.utils.Utils; import jadx.gui.jobs.TaskStatus; import jadx.gui.settings.JadxProject; import jadx.gui.settings.JadxSettings; +import jadx.gui.treemodel.JNode; +import jadx.gui.treemodel.JRoot; import jadx.gui.ui.MainWindow; +import jadx.gui.ui.TabbedPane; import jadx.gui.ui.filedialog.FileDialogWrapper; import jadx.gui.ui.filedialog.FileOpenMode; +import jadx.gui.ui.panel.ContentPanel; import jadx.gui.utils.NLS; import jadx.gui.utils.UiUtils; import jadx.gui.utils.ui.ActionHandler; @@ -41,8 +45,8 @@ public class RenameMappingsGui { private final MainWindow mainWindow; - // private MappingFormat currentMappingFormat; private boolean renamesChanged = false; + private JInputMapping mappingNode; private transient JMenu openMappingsMenu; private transient Action saveMappingsAction; @@ -52,6 +56,7 @@ public class RenameMappingsGui { public RenameMappingsGui(MainWindow mainWindow) { this.mainWindow = mainWindow; mainWindow.addLoadListener(this::onLoad); + mainWindow.addTreeUpdateListener(this::treeUpdate); } public void addMenuActions(JMenu menu) { @@ -84,6 +89,7 @@ public class RenameMappingsGui { private boolean onLoad(boolean loaded) { renamesChanged = false; + mappingNode = null; if (loaded) { RootNode rootNode = mainWindow.getWrapper().getRootNode(); rootNode.registerCodeDataUpdateListener(codeData -> onRename()); @@ -119,6 +125,29 @@ public class RenameMappingsGui { closeMappingsAction.setEnabled(project.getMappingsPath() != null); } + private void treeUpdate(JRoot treeRoot) { + if (mappingNode != null) { + // already added + return; + } + Path mappingsPath = mainWindow.getProject().getMappingsPath(); + if (mappingsPath == null) { + return; + } + JNode node = treeRoot.followStaticPath("JInputs"); + JNode currentNode = node.removeNode(n -> n.getClass().equals(JInputMapping.class)); + if (currentNode != null) { + // close opened tab + TabbedPane tabbedPane = mainWindow.getTabbedPane(); + ContentPanel openedTab = tabbedPane.getOpenTabs().get(currentNode); + if (openedTab != null) { + tabbedPane.closeCodePanel(openedTab); + } + } + mappingNode = new JInputMapping(mappingsPath); + node.add(mappingNode); + } + private void openMappings(MappingFormat mappingFormat, boolean inverted) { FileDialogWrapper fileDialog = new FileDialogWrapper(mainWindow, FileOpenMode.CUSTOM_OPEN); fileDialog.setTitle(NLS.str("file.open_mappings")); @@ -205,7 +234,10 @@ public class RenameMappingsGui { options.put(RenameMappingsOptions.FORMAT_OPT, mappingFormat.name()); options.put(RenameMappingsOptions.INVERT_OPT, "no"); }); - saveInBackground(mappingFormat, savePath, s -> mainWindow.reopen()); + saveInBackground(mappingFormat, savePath, s -> { + mappingNode = null; + mainWindow.reloadTree(); + }); } private void saveInBackground(MappingFormat mappingFormat, Path savePath, Consumer onFinishUiRunnable) { diff --git a/jadx-gui/src/main/java/jadx/gui/settings/TabStateViewAdapter.java b/jadx-gui/src/main/java/jadx/gui/settings/TabStateViewAdapter.java index 82227600b..5e047acc6 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/TabStateViewAdapter.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/TabStateViewAdapter.java @@ -68,7 +68,7 @@ public class TabStateViewAdapter { .searchNode(node -> node instanceof JInputScript && node.getName().equals(tvs.getTabPath())); case "mapping": - return mw.getTreeRoot().followStaticPath("JInputs", "JInputMapping"); + return mw.getTreeRoot().followStaticPath("JInputs").searchNode(node -> node instanceof JInputMapping); } return null; } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java index a95e4688a..38c7a456c 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java @@ -1,6 +1,5 @@ package jadx.gui.treemodel; -import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Iterator; @@ -11,7 +10,6 @@ import javax.swing.ImageIcon; import jadx.core.utils.files.FileUtils; import jadx.gui.JadxWrapper; -import jadx.gui.plugins.mappings.JInputMapping; import jadx.gui.settings.JadxProject; import jadx.gui.utils.NLS; import jadx.gui.utils.UiUtils; @@ -35,11 +33,6 @@ public class JInputs extends JNode { add(new JInputFiles(files)); add(new JInputScripts(scripts)); - - Path mappingsPath = project.getMappingsPath(); - if (mappingsPath != null && Files.isRegularFile(mappingsPath)) { - add(new JInputMapping(mappingsPath)); - } } @Override diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java index 52a3f70f6..2900de1cf 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java @@ -111,7 +111,7 @@ public abstract class JNode extends DefaultMutableTreeNode implements Comparable } public @Nullable JNode searchNode(Predicate filter) { - Enumeration en = this.breadthFirstEnumeration(); + Enumeration en = this.children(); while (en.hasMoreElements()) { JNode node = (JNode) en.nextElement(); if (filter.test(node)) { @@ -121,6 +121,21 @@ public abstract class JNode extends DefaultMutableTreeNode implements Comparable return null; } + /** + * Remove and return first found node + */ + public @Nullable JNode removeNode(Predicate filter) { + Enumeration en = this.children(); + while (en.hasMoreElements()) { + JNode node = (JNode) en.nextElement(); + if (filter.test(node)) { + this.remove(node); + return node; + } + } + return null; + } + private static final Comparator COMPARATOR = Comparator .comparing(JNode::makeLongString) .thenComparingInt(JNode::getPos); 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 9bac6f8c2..1cc2e6397 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -37,6 +37,7 @@ import java.util.Locale; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import javax.swing.AbstractAction; import javax.swing.Action; @@ -212,6 +213,7 @@ public class MainWindow extends JFrame { private transient @Nullable JDebuggerPanel debuggerPanel; private final List loadListeners = new ArrayList<>(); + private final List> treeUpdateListener = new ArrayList<>(); private boolean loaded; private JMenu pluginsMenu; @@ -689,6 +691,7 @@ public class MainWindow extends JFrame { public void reloadTree() { treeReloading = true; + treeUpdateListener.forEach(listener -> listener.accept(treeRoot)); treeModel.reload(); List treeExpansions = project.getTreeExpansions(); @@ -1526,6 +1529,10 @@ public class MainWindow extends JFrame { loadListeners.removeIf(listener -> listener.update(loaded)); } + public void addTreeUpdateListener(Consumer listener) { + treeUpdateListener.add(listener); + } + public JadxWrapper getWrapper() { return wrapper; }