From 0a80622efae2fd54df3ed991eb856b3718d6820c Mon Sep 17 00:00:00 2001 From: ramidzkh Date: Tue, 13 Sep 2022 03:28:25 +1000 Subject: Nested packages in Swing UI (#458) * WIP nested packages * Fix deobfuscated panel package having obfuscated packages * Remove stream * Mass toggle classes obfuscation status from selector * Fix deobfuscated classes with the same name being hidden from class selectors * Open classes by pressing enter--- .../main/java/cuchaz/enigma/gui/ClassSelector.java | 401 ++++----------------- .../src/main/java/cuchaz/enigma/gui/Gui.java | 26 +- .../main/java/cuchaz/enigma/gui/GuiController.java | 6 +- .../java/cuchaz/enigma/gui/NestedPackages.java | 124 +++++++ .../enigma/gui/node/ClassSelectorPackageNode.java | 4 +- 5 files changed, 209 insertions(+), 352 deletions(-) create mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java (limited to 'enigma-swing') 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 57b23c9a..b7d3c4ef 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java @@ -11,40 +11,33 @@ package cuchaz.enigma.gui; -import java.awt.Component; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.*; - -import javax.annotation.Nullable; -import javax.swing.JTree; -import javax.swing.event.CellEditorListener; -import javax.swing.event.ChangeEvent; -import javax.swing.tree.*; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; import cuchaz.enigma.gui.node.ClassSelectorClassNode; -import cuchaz.enigma.gui.node.ClassSelectorPackageNode; import cuchaz.enigma.gui.util.GuiUtil; -import cuchaz.enigma.translation.Translator; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.utils.validation.ValidationContext; +import javax.swing.*; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.tree.*; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; +import java.util.*; + public class ClassSelector extends JTree { public static final Comparator DEOBF_CLASS_COMPARATOR = Comparator.comparing(ClassEntry::getFullName); + private final Comparator comparator; private final GuiController controller; - private DefaultMutableTreeNode rootNodes; + private NestedPackages packageManager; private ClassSelectionListener selectionListener; private RenameSelectionListener renameSelectionListener; - private Comparator comparator; - - private final Map displayedObfToDeobf = new HashMap<>(); public ClassSelector(Gui gui, Comparator comparator, boolean isRenamable) { this.comparator = comparator; @@ -69,6 +62,30 @@ public class ClassSelector extends JTree { } } }); + addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + TreePath[] paths = getSelectionPaths(); + + if (paths != null) { + if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_O) { + for (TreePath path : paths) { + if (path.getLastPathComponent() instanceof ClassSelectorClassNode node) { + gui.toggleMappingFromEntry(node.getObfEntry()); + } + } + } + + if (selectionListener != null && e.getKeyCode() == KeyEvent.VK_ENTER) { + for (TreePath path : paths) { + if (path.getLastPathComponent() instanceof ClassSelectorClassNode node) { + selectionListener.onSelectClass(node.getObfEntry()); + } + } + } + } + } + }); final DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() { { @@ -143,19 +160,6 @@ public class ClassSelector extends JTree { this.renameSelectionListener = null; } - public boolean isDuplicate(Object[] nodes, String data) { - int count = 0; - - for (Object node : nodes) { - if (node.toString().equals(data)) { - count++; - if (count == 2) - return true; - } - } - return false; - } - public void setSelectionListener(ClassSelectionListener val) { this.selectionListener = val; } @@ -165,376 +169,109 @@ public class ClassSelector extends JTree { } public void setClasses(Collection classEntries) { - displayedObfToDeobf.clear(); + List state = getExpansionState(); - List state = getExpansionState(this); if (classEntries == null) { setModel(null); return; } - Translator translator = controller.project.getMapper().getDeobfuscator(); - - // build the package names - Map packages = Maps.newHashMap(); - for (ClassEntry obfClass : classEntries) { - ClassEntry deobfClass = translator.translate(obfClass); - packages.put(deobfClass.getPackageName(), null); - } + // update the tree control + packageManager = new NestedPackages(classEntries, comparator, controller.project.getMapper()); + setModel(new DefaultTreeModel(packageManager.getRoot())); - // sort the packages - List sortedPackageNames = Lists.newArrayList(packages.keySet()); - sortedPackageNames.sort((a, b) -> - { - // I can never keep this rule straight when writing these damn things... - // a < b => -1, a == b => 0, a > b => +1 - - if (b == null || a == null) { - return 0; - } - - String[] aparts = a.split("/"); - String[] bparts = b.split("/"); - for (int i = 0; true; i++) { - if (i >= aparts.length) { - return -1; - } else if (i >= bparts.length) { - return 1; - } - - int result = aparts[i].compareTo(bparts[i]); - if (result != 0) { - return result; - } - } - }); - - // create the rootNodes node and the package nodes - rootNodes = new DefaultMutableTreeNode(); - for (String packageName : sortedPackageNames) { - ClassSelectorPackageNode node = new ClassSelectorPackageNode(packageName); - packages.put(packageName, node); - rootNodes.add(node); - } - - // put the classes into packages - Multimap packagedClassEntries = ArrayListMultimap.create(); - for (ClassEntry obfClass : classEntries) { - ClassEntry deobfClass = translator.translate(obfClass); - packagedClassEntries.put(deobfClass.getPackageName(), obfClass); - } - - // build the class nodes - for (String packageName : packagedClassEntries.keySet()) { - // sort the class entries - List classEntriesInPackage = Lists.newArrayList(packagedClassEntries.get(packageName)); - classEntriesInPackage.sort((o1, o2) -> comparator.compare(translator.translate(o1), translator.translate(o2))); - - // create the nodes in order - for (ClassEntry obfClass : classEntriesInPackage) { - ClassEntry deobfClass = translator.translate(obfClass); - ClassSelectorPackageNode node = packages.get(packageName); - ClassSelectorClassNode classNode = new ClassSelectorClassNode(obfClass, deobfClass); - displayedObfToDeobf.put(obfClass, deobfClass); - node.add(classNode); - } - } - - // finally, update the tree control - setModel(new DefaultTreeModel(rootNodes)); - - restoreExpansionState(this, state); + restoreExpansionState(state); } public ClassEntry getSelectedClass() { if (!isSelectionEmpty()) { Object selectedNode = getSelectionPath().getLastPathComponent(); + if (selectedNode instanceof ClassSelectorClassNode classNode) { return classNode.getClassEntry(); } } - return null; - } - public String getSelectedPackage() { - if (!isSelectionEmpty()) { - Object selectedNode = getSelectionPath().getLastPathComponent(); - if (selectedNode instanceof ClassSelectorPackageNode packageNode) { - return packageNode.getPackageName(); - } else if (selectedNode instanceof ClassSelectorClassNode classNode) { - return classNode.getClassEntry().getPackageName(); - } - } return null; } - public boolean isDescendant(TreePath path1, TreePath path2) { - int count1 = path1.getPathCount(); - int count2 = path2.getPathCount(); - if (count1 <= count2) { - return false; - } - while (count1 != count2) { - path1 = path1.getParentPath(); - count1--; - } - return path1.equals(path2); - } - public enum State { EXPANDED, SELECTED } - public static class StateEntry { - public final State state; - public final TreePath path; - - public StateEntry(State state, TreePath path) { - this.state = state; - this.path = path; - } + public record StateEntry(State state, TreePath path) { } - public List getExpansionState(JTree tree) { + public List getExpansionState() { List state = new ArrayList<>(); - int rowCount = tree.getRowCount(); + int rowCount = getRowCount(); for (int i = 0; i < rowCount; i++) { - TreePath path = tree.getPathForRow(i); - if (tree.isPathSelected(path)) { + TreePath path = getPathForRow(i); + if (isPathSelected(path)) { state.add(new StateEntry(State.SELECTED, path)); } - if (tree.isExpanded(path)) { + if (isExpanded(path)) { state.add(new StateEntry(State.EXPANDED, path)); } } return state; } - public void restoreExpansionState(JTree tree, List expansionState) { - tree.clearSelection(); + public void restoreExpansionState(List expansionState) { + clearSelection(); for (StateEntry entry : expansionState) { switch (entry.state) { - case SELECTED -> tree.addSelectionPath(entry.path); - case EXPANDED -> tree.expandPath(entry.path); + case SELECTED -> addSelectionPath(entry.path); + case EXPANDED -> expandPath(entry.path); } } } - public List packageNodes() { - List nodes = Lists.newArrayList(); - DefaultMutableTreeNode root = (DefaultMutableTreeNode) getModel().getRoot(); - Enumeration children = root.children(); - while (children.hasMoreElements()) { - ClassSelectorPackageNode packageNode = (ClassSelectorPackageNode) children.nextElement(); - nodes.add(packageNode); - } - return nodes; - } - - public List classNodes(ClassSelectorPackageNode packageNode) { - List nodes = Lists.newArrayList(); - Enumeration children = packageNode.children(); - while (children.hasMoreElements()) { - ClassSelectorClassNode classNode = (ClassSelectorClassNode) children.nextElement(); - nodes.add(classNode); - } - return nodes; - } - public void expandPackage(String packageName) { if (packageName == null) { return; } - for (ClassSelectorPackageNode packageNode : packageNodes()) { - if (packageNode.getPackageName().equals(packageName)) { - expandPath(new TreePath(new Object[]{getModel().getRoot(), packageNode})); - return; - } - } + + expandPath(packageManager.getPackagePath(packageName)); } public void expandAll() { - for (ClassSelectorPackageNode packageNode : packageNodes()) { - expandPath(new TreePath(new Object[]{getModel().getRoot(), packageNode})); + for (DefaultMutableTreeNode packageNode : packageManager.getPackageNodes()) { + expandPath(new TreePath(packageNode.getPath())); } } public void collapseAll() { - for (ClassSelectorPackageNode packageNode : packageNodes()) { - collapsePath(new TreePath(new Object[]{getModel().getRoot(), packageNode})); - } - } - - public ClassEntry getFirstClass() { - ClassSelectorPackageNode packageNode = packageNodes().get(0); - if (packageNode != null) { - ClassSelectorClassNode classNode = classNodes(packageNode).get(0); - if (classNode != null) { - return classNode.getClassEntry(); - } - } - return null; - } - - public ClassSelectorPackageNode getPackageNode(ClassEntry entry) { - String packageName = entry.getPackageName(); - if (packageName == null) { - packageName = "(none)"; - } - for (ClassSelectorPackageNode packageNode : packageNodes()) { - if (packageNode.getPackageName().equals(packageName)) { - return packageNode; - } + for (DefaultMutableTreeNode packageNode : packageManager.getPackageNodes()) { + collapsePath(new TreePath(packageNode.getPath())); } - return null; - } - - @Nullable - public ClassEntry getDisplayedDeobf(ClassEntry obfEntry) { - return displayedObfToDeobf.get(obfEntry); - } - - public ClassSelectorPackageNode getPackageNode(ClassSelector selector, ClassEntry entry) { - ClassSelectorPackageNode packageNode = getPackageNode(entry); - - if (selector != null && packageNode == null && selector.getPackageNode(entry) != null) - return selector.getPackageNode(entry); - return packageNode; - } - - public ClassEntry getNextClass(ClassEntry entry) { - boolean foundIt = false; - for (ClassSelectorPackageNode packageNode : packageNodes()) { - if (!foundIt) { - // skip to the package with our target in it - if (packageNode.getPackageName().equals(entry.getPackageName())) { - for (ClassSelectorClassNode classNode : classNodes(packageNode)) { - if (!foundIt) { - if (classNode.getClassEntry().equals(entry)) { - foundIt = true; - } - } else { - // return the next class - return classNode.getClassEntry(); - } - } - } - } else { - // return the next class - ClassSelectorClassNode classNode = classNodes(packageNode).get(0); - if (classNode != null) { - return classNode.getClassEntry(); - } - } - } - return null; } public void setSelectionClass(ClassEntry classEntry) { expandPackage(classEntry.getPackageName()); - for (ClassSelectorPackageNode packageNode : packageNodes()) { - for (ClassSelectorClassNode classNode : classNodes(packageNode)) { - if (classNode.getClassEntry().equals(classEntry)) { - TreePath path = new TreePath(new Object[]{getModel().getRoot(), packageNode, classNode}); - setSelectionPath(path); - scrollPathToVisible(path); - } - } - } - } + ClassSelectorClassNode node = packageManager.getClassNode(classEntry); - public void removeNode(ClassSelectorPackageNode packageNode, ClassEntry entry) { - DefaultTreeModel model = (DefaultTreeModel) getModel(); - - if (packageNode == null) - return; - - for (int i = 0; i < packageNode.getChildCount(); i++) { - DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) packageNode.getChildAt(i); - if (childNode.getUserObject() instanceof ClassEntry && childNode.getUserObject().equals(entry)) { - model.removeNodeFromParent(childNode); - if (childNode instanceof ClassSelectorClassNode) { - displayedObfToDeobf.remove(((ClassSelectorClassNode) childNode).getObfEntry()); - } - break; - } + if (node != null) { + TreePath path = new TreePath(node.getPath()); + setSelectionPath(path); + scrollPathToVisible(path); } } - public void removeNodeIfEmpty(ClassSelectorPackageNode packageNode) { - if (packageNode != null && packageNode.getChildCount() == 0) - ((DefaultTreeModel) getModel()).removeNodeFromParent(packageNode); - } - public void moveClassIn(ClassEntry classEntry) { removeEntry(classEntry); - insertNode(classEntry); - } - - public void moveClassOut(ClassEntry classEntry) { - removeEntry(classEntry); + packageManager.addEntry(classEntry); } - private void removeEntry(ClassEntry classEntry) { - ClassEntry previousDeobf = displayedObfToDeobf.get(classEntry); - if (previousDeobf != null) { - ClassSelectorPackageNode packageNode = getPackageNode(previousDeobf); - removeNode(packageNode, previousDeobf); - removeNodeIfEmpty(packageNode); - } - } - - public ClassSelectorPackageNode getOrCreatePackage(ClassEntry entry) { - DefaultTreeModel model = (DefaultTreeModel) getModel(); - ClassSelectorPackageNode newPackageNode = getPackageNode(entry); - if (newPackageNode == null) { - newPackageNode = new ClassSelectorPackageNode(entry.getPackageName()); - model.insertNodeInto(newPackageNode, (MutableTreeNode) model.getRoot(), getPlacementIndex(newPackageNode)); - } - return newPackageNode; - } - - public void insertNode(ClassEntry obfEntry) { - ClassEntry deobfEntry = controller.project.getMapper().deobfuscate(obfEntry); - ClassSelectorPackageNode packageNode = getOrCreatePackage(deobfEntry); - - DefaultTreeModel model = (DefaultTreeModel) getModel(); - ClassSelectorClassNode classNode = new ClassSelectorClassNode(obfEntry, deobfEntry); - model.insertNodeInto(classNode, packageNode, getPlacementIndex(packageNode, classNode)); - - displayedObfToDeobf.put(obfEntry, deobfEntry); + public void removeEntry(ClassEntry classEntry) { + packageManager.removeClassNode(classEntry); } public void reload() { DefaultTreeModel model = (DefaultTreeModel) getModel(); - model.reload(rootNodes); - } - - private int getPlacementIndex(ClassSelectorPackageNode newPackageNode, ClassSelectorClassNode classNode) { - List classNodes = classNodes(newPackageNode); - classNodes.add(classNode); - classNodes.sort((a, b) -> comparator.compare(a.getClassEntry(), b.getClassEntry())); - for (int i = 0; i < classNodes.size(); i++) - if (classNodes.get(i) == classNode) - return i; - - return 0; - } - - private int getPlacementIndex(ClassSelectorPackageNode newPackageNode) { - List packageNodes = packageNodes(); - if (!packageNodes.contains(newPackageNode)) { - packageNodes.add(newPackageNode); - packageNodes.sort(Comparator.comparing(ClassSelectorPackageNode::toString)); - } - - for (int i = 0; i < packageNodes.size(); i++) - if (packageNodes.get(i) == newPackageNode) - return i; - - return 0; + model.reload(packageManager.getRoot()); } public interface ClassSelectionListener { 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 cac0ea89..5a1e3d8b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java @@ -376,7 +376,10 @@ public class Gui { if (cursorReference == null) return; Entry obfEntry = cursorReference.entry; + toggleMappingFromEntry(obfEntry); + } + public void toggleMappingFromEntry(Entry obfEntry) { if (this.controller.project.getMapper().getDeobfMapping(obfEntry).targetName() != null) { validateImmediateAction(vc -> this.controller.applyChange(vc, EntryChange.modify(obfEntry).clearDeobfName())); } else { @@ -384,17 +387,6 @@ public class Gui { } } - private TreePath getPathToRoot(TreeNode node) { - List nodes = Lists.newArrayList(); - TreeNode n = node; - do { - nodes.add(n); - n = n.getParent(); - } while (n != null); - Collections.reverse(nodes); - return new TreePath(nodes.toArray()); - } - public void showDiscardDiag(Function callback, String... options) { int response = JOptionPane.showOptionDialog(this.mainWindow.frame(), I18n.translate("prompt.close.summary"), I18n.translate("prompt.close.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[2]); @@ -492,20 +484,20 @@ public class Gui { public void moveClassTree(Entry obfEntry, boolean isOldOb, boolean isNewOb) { ClassEntry classEntry = obfEntry.getContainingClass(); - List stateDeobf = this.deobfPanel.deobfClasses.getExpansionState(this.deobfPanel.deobfClasses); - List stateObf = this.obfPanel.obfClasses.getExpansionState(this.obfPanel.obfClasses); + List stateDeobf = this.deobfPanel.deobfClasses.getExpansionState(); + List stateObf = this.obfPanel.obfClasses.getExpansionState(); // Ob -> deob if (!isNewOb) { this.deobfPanel.deobfClasses.moveClassIn(classEntry); - this.obfPanel.obfClasses.moveClassOut(classEntry); + this.obfPanel.obfClasses.removeEntry(classEntry); this.deobfPanel.deobfClasses.reload(); this.obfPanel.obfClasses.reload(); } // Deob -> ob else if (!isOldOb) { this.obfPanel.obfClasses.moveClassIn(classEntry); - this.deobfPanel.deobfClasses.moveClassOut(classEntry); + this.deobfPanel.deobfClasses.removeEntry(classEntry); this.deobfPanel.deobfClasses.reload(); this.obfPanel.obfClasses.reload(); } @@ -518,8 +510,8 @@ public class Gui { this.deobfPanel.deobfClasses.reload(); } - this.deobfPanel.deobfClasses.restoreExpansionState(this.deobfPanel.deobfClasses, stateDeobf); - this.obfPanel.obfClasses.restoreExpansionState(this.obfPanel.obfClasses, stateObf); + this.deobfPanel.deobfClasses.restoreExpansionState(stateDeobf); + this.obfPanel.obfClasses.restoreExpansionState(stateObf); } public ObfPanel getObfPanel() { diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index 67ac6625..47a854f9 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java @@ -52,6 +52,7 @@ import cuchaz.enigma.source.DecompiledClassSource; import cuchaz.enigma.source.DecompilerService; import cuchaz.enigma.source.SourceIndex; import cuchaz.enigma.source.Token; +import cuchaz.enigma.translation.TranslateResult; import cuchaz.enigma.translation.Translator; import cuchaz.enigma.translation.mapping.*; import cuchaz.enigma.translation.mapping.serde.MappingFormat; @@ -381,10 +382,11 @@ public class GuiController implements ClientPacketHandler { return; } - ClassEntry deobfEntry = mapper.deobfuscate(entry); + TranslateResult result = mapper.extendedDeobfuscate(entry); + ClassEntry deobfEntry = result.getValue(); List obfService = enigma.getServices().get(ObfuscationTestService.TYPE); - boolean obfuscated = deobfEntry.equals(entry); + boolean obfuscated = result.isObfuscated() && deobfEntry.equals(entry); if (obfuscated && !obfService.isEmpty()) { if (obfService.stream().anyMatch(service -> service.testDeobfuscated(entry))) { diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java new file mode 100644 index 00000000..309f9106 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java @@ -0,0 +1,124 @@ +package cuchaz.enigma.gui; + +import cuchaz.enigma.gui.node.ClassSelectorClassNode; +import cuchaz.enigma.gui.node.ClassSelectorPackageNode; +import cuchaz.enigma.translation.mapping.EntryRemapper; +import cuchaz.enigma.translation.representation.entry.ClassEntry; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +public class NestedPackages { + + private final DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + private final Map packageToNode = new HashMap<>(); + private final Map classToNode = new HashMap<>(); + private final EntryRemapper remapper; + private final Comparator comparator; + + public NestedPackages(Iterable entries, Comparator entryComparator, EntryRemapper remapper) { + this.remapper = remapper; + this.comparator = (a, b) -> { + if (a instanceof ClassSelectorPackageNode pA) { + if (b instanceof ClassSelectorPackageNode pB) { + return pA.getPackageName().compareTo(pB.getPackageName()); + } else { + return -1; + } + } else if (a instanceof ClassSelectorClassNode cA) { + if (b instanceof ClassSelectorClassNode cB) { + return entryComparator.compare(cA.getClassEntry(), cB.getClassEntry()); + } else { + return 1; + } + } + + return 0; + }; + + for (var entry : entries) { + addEntry(entry); + } + } + + public void addEntry(ClassEntry entry) { + var translated = remapper.deobfuscate(entry); + var me = new ClassSelectorClassNode(entry, translated); + classToNode.put(entry, me); + insert(getPackage(translated.getPackageName()), me); + } + + public DefaultMutableTreeNode getPackage(String packageName) { + var node = packageToNode.get(packageName); + + if (packageName == null) { + return root; + } + + if (node == null) { + node = new ClassSelectorPackageNode(packageName); + insert(getPackage(ClassEntry.getParentPackage(packageName)), node); + packageToNode.put(packageName, node); + } + + return node; + } + + public DefaultMutableTreeNode getRoot() { + return root; + } + + public TreePath getPackagePath(String packageName) { + var node = packageToNode.getOrDefault(packageName, root); + return new TreePath(node.getPath()); + } + + public ClassSelectorClassNode getClassNode(ClassEntry entry) { + return classToNode.get(entry); + } + + public void removeClassNode(ClassEntry entry) { + var node = classToNode.remove(entry); + + if (node != null) { + node.removeFromParent(); + // remove dangling packages + var packageNode = packageToNode.get(entry.getPackageName()); + + while (packageNode != null && packageNode.getChildCount() == 0) { + var theNode = packageNode; + packageNode = (DefaultMutableTreeNode) packageNode.getParent(); + theNode.removeFromParent(); + + if (theNode instanceof ClassSelectorPackageNode pn) { + packageToNode.remove(pn.getPackageName()); + } + } + } + } + + public Collection getPackageNodes() { + return packageToNode.values(); + } + + private void insert(DefaultMutableTreeNode parent, MutableTreeNode child) { + var index = 0; + var children = parent.children(); + + while (children.hasMoreElements()) { + if (comparator.compare(children.nextElement(), child) < 0) { + index++; + } else { + break; + } + } + + parent.insert(child, index); + } +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java index caa985c9..c1c7d387 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java @@ -11,6 +11,8 @@ package cuchaz.enigma.gui.node; +import cuchaz.enigma.translation.representation.entry.ClassEntry; + import javax.swing.tree.DefaultMutableTreeNode; public class ClassSelectorPackageNode extends DefaultMutableTreeNode { @@ -39,7 +41,7 @@ public class ClassSelectorPackageNode extends DefaultMutableTreeNode { @Override public String toString() { - return !packageName.equals("(none)") ? this.packageName : "(none)"; + return !packageName.equals("(none)") ? ClassEntry.getNameInPackage(this.packageName) : "(none)"; } @Override -- cgit v1.2.3