diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java index 5f53f4d8..adf07331 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java @@ -11,6 +11,8 @@ package cuchaz.enigma.gui; +import cuchaz.enigma.gui.node.ClassSelectorPackageNode; + import java.awt.Component; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; @@ -150,14 +152,26 @@ public void editingStopped(ChangeEvent e) { } if (allowEdit && renameSelectionListener != null) { - Object prevData = node.getUserObject(); - Object objectData = node.getUserObject() instanceof ClassEntry ? new ClassEntry(((ClassEntry) prevData).getPackageName() + "/" + data) : data; gui.validateImmediateAction(vc -> { - renameSelectionListener.onSelectionRename(vc, node.getUserObject(), objectData, node); - - if (vc.canProceed()) { - node.setUserObject(objectData); // Make sure that it's modified + String parentName; + + if(node instanceof ClassSelectorPackageNode packageNode) { + String packageName = packageNode.getPackageName(); + int lastSlash = packageName.lastIndexOf("/"); + if(lastSlash != -1) { + parentName = packageName.substring(0, lastSlash); + } else { + parentName = ""; + } + } else if(node instanceof ClassSelectorClassNode classNode) { + parentName = classNode.getClassEntry().getPackageName(); } else { + throw new IllegalStateException("unknown node type " + node.getClass().getSimpleName()); + } + + renameSelectionListener.onSelectionRename(vc, parentName + "/" + data, node); + + if (!vc.canProceed()) { editor.cancelCellEditing(); } }); @@ -305,6 +319,6 @@ public interface ClassSelectionListener { } public interface RenameSelectionListener { - void onSelectionRename(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node); + void onSelectionRename(ValidationContext vc, String targetName, DefaultMutableTreeNode node); } } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index 05146d4a..db08fbe3 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java @@ -16,6 +16,7 @@ import java.awt.Point; import java.awt.event.ActionEvent; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; @@ -57,6 +58,8 @@ import cuchaz.enigma.gui.elements.MainWindow; import cuchaz.enigma.gui.elements.MenuBar; import cuchaz.enigma.gui.elements.ValidatableUi; +import cuchaz.enigma.gui.node.ClassSelectorClassNode; +import cuchaz.enigma.gui.node.ClassSelectorPackageNode; import cuchaz.enigma.gui.panels.DeobfPanel; import cuchaz.enigma.gui.panels.EditorPanel; import cuchaz.enigma.gui.panels.IdentifierPanel; @@ -482,32 +485,54 @@ public void redraw() { frame.repaint(); } - public void onRenameFromClassTree(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node) { - if (data instanceof String) { - // package rename - for (int i = 0; i < node.getChildCount(); i++) { - DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) node.getChildAt(i); - ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); - ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); + public void onRenameFromClassTree(ValidationContext vc, String targetName, DefaultMutableTreeNode node) { + List> task = new ArrayList<>(); + onRenameFromClassTree(targetName, node, task); - onRenameFromClassTree(vc, prevDataChild, dataChild, node); - } + task.forEach(c -> this.controller.validateChange(vc, c)); - node.setUserObject(data); - // Ob package will never be modified, just reload deob view - this.deobfPanel.deobfClasses.reload(); - } else if (data instanceof ClassEntry) { - // class rename + if (!vc.canProceed()) { + return; + } - // TODO optimize reverse class lookup, although it looks like it's - // fast enough for now - EntryRemapper mapper = this.controller.project.getMapper(); - ClassEntry deobf = (ClassEntry) prevData; - ClassEntry obf = mapper.getObfToDeobf().getAllEntries().filter(e -> e instanceof ClassEntry).map(e -> (ClassEntry) e).filter(e -> mapper.deobfuscate(e).equals(deobf)).findAny().orElse(deobf); + task.forEach(c -> this.controller.applyChange(vc, c)); + } - this.controller.applyChange(vc, EntryChange.modify(obf).withDeobfName(((ClassEntry) data).getFullName())); + private void onRenameFromClassTree(String targetName, DefaultMutableTreeNode node, List> entryOps) { + if (targetName.startsWith("/")) { + targetName = targetName.substring(1); + } + + if (node instanceof ClassSelectorPackageNode) { + for (int i = 0; i < node.getChildCount(); i++) { + String childName; + DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i); + + if (child instanceof ClassSelectorPackageNode packageNode) { + String[] parts = packageNode.getPackageName().split("/"); + childName = targetName + "/" + parts[parts.length - 1]; + } else if (child instanceof ClassSelectorClassNode classNode) { + childName = targetName + "/" + classNode.getClassEntry().getSimpleName(); + } else { + throw new IllegalStateException(String.format("unhandled rename object type: '%s'", + child.getClass())); + } + + onRenameFromClassTree(childName, child, entryOps); + } + } else if (node instanceof ClassSelectorClassNode classSelectorClassNode) { + EntryRemapper mapper = this.controller.project.getMapper(); + ClassEntry deobf = classSelectorClassNode.getClassEntry(); + ClassEntry obf = mapper.getObfToDeobf().getAllEntries() + .filter(e -> e instanceof ClassEntry) + .map(e -> (ClassEntry) e) + .filter(e -> mapper.deobfuscate(e).equals(deobf)) + .findAny() + .orElse(deobf); + + entryOps.add(EntryChange.modify(obf).withDeobfName(targetName)); } else { - throw new IllegalStateException(String.format("unhandled rename object data: '%s'", data)); + throw new IllegalStateException(String.format("unhandled rename object type: '%s'", node.getClass())); } }