From 3a50fea029b9f0355cba1bf8f9c5bb941298bc4a Mon Sep 17 00:00:00 2001 From: Thog Date: Tue, 23 Aug 2016 13:49:24 +0200 Subject: Add the ability to rename package and classes in panels --- src/main/java/cuchaz/enigma/Main.java | 2 +- .../java/cuchaz/enigma/gui/ClassMatchingGui.java | 8 +- src/main/java/cuchaz/enigma/gui/ClassSelector.java | 133 +++++++++++++++++---- src/main/java/cuchaz/enigma/gui/Gui.java | 19 +++ .../java/cuchaz/enigma/gui/MemberMatchingGui.java | 10 +- .../enigma/gui/node/ClassSelectorClassNode.java | 13 ++ .../enigma/gui/node/ClassSelectorPackageNode.java | 7 ++ .../java/cuchaz/enigma/gui/panels/PanelDeobf.java | 5 +- .../java/cuchaz/enigma/gui/panels/PanelObf.java | 5 +- 9 files changed, 165 insertions(+), 37 deletions(-) diff --git a/src/main/java/cuchaz/enigma/Main.java b/src/main/java/cuchaz/enigma/Main.java index a1007cf..9dad501 100644 --- a/src/main/java/cuchaz/enigma/Main.java +++ b/src/main/java/cuchaz/enigma/Main.java @@ -33,7 +33,7 @@ public class Main { } // DEBUG - //gui.getController().openDeclaration(new ClassEntry("none/asj")); + //gui.getController().openDeclaration(new ClassEntry("net/minecraft/item/Item")); } private static File getFile(String path) { diff --git a/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java b/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java index ec63900..3cd1705 100644 --- a/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java +++ b/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java @@ -131,8 +131,8 @@ public class ClassMatchingGui { sourceTypePanel.add(button); } - m_sourceClasses = new ClassSelector(ClassSelector.DEOBF_CLASS_COMPARATOR); - m_sourceClasses.setListener(classEntry -> setSourceClass(classEntry)); + m_sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR); + m_sourceClasses.setSelectionListener(this::setSourceClass); JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); sourcePanel.add(sourceScroller); @@ -147,8 +147,8 @@ public class ClassMatchingGui { destPanel.add(m_top10Matches); m_top10Matches.addActionListener(event -> toggleTop10Matches()); - m_destClasses = new ClassSelector(ClassSelector.DEOBF_CLASS_COMPARATOR); - m_destClasses.setListener(this::setDestClass); + m_destClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR); + m_destClasses.setSelectionListener(this::setDestClass); JScrollPane destScroller = new JScrollPane(m_destClasses); destPanel.add(destScroller); diff --git a/src/main/java/cuchaz/enigma/gui/ClassSelector.java b/src/main/java/cuchaz/enigma/gui/ClassSelector.java index 3df9042..ed0f6c8 100644 --- a/src/main/java/cuchaz/enigma/gui/ClassSelector.java +++ b/src/main/java/cuchaz/enigma/gui/ClassSelector.java @@ -14,35 +14,42 @@ 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.mapping.ClassEntry; +import cuchaz.enigma.throwables.IllegalNameException; +import javax.swing.*; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.tree.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.*; -import javax.swing.JTree; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; - -import cuchaz.enigma.gui.node.ClassSelectorClassNode; -import cuchaz.enigma.gui.node.ClassSelectorPackageNode; -import cuchaz.enigma.mapping.ClassEntry; - public class ClassSelector extends JTree { public static final Comparator DEOBF_CLASS_COMPARATOR = (a, b) -> a.getName().compareTo(b.getName()); + private DefaultMutableTreeNode rootNodes; public interface ClassSelectionListener { void onSelectClass(ClassEntry classEntry); } - private ClassSelectionListener listener; + public interface RenameSelectionListener { + void onSelectionRename(Object prevData, Object data, DefaultMutableTreeNode node); + } + + private ClassSelectionListener selectionListener; + private RenameSelectionListener renameSelectionListener; private Comparator comparator; - public ClassSelector(Comparator comparator) { + public ClassSelector(Gui gui, Comparator comparator) { this.comparator = comparator; // configure the tree control + setEditable(gui != null); setRootVisible(false); setShowsRootHandles(false); setModel(null); @@ -51,23 +58,109 @@ public class ClassSelector extends JTree { addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent event) { - if (listener != null && event.getClickCount() == 2) { + if (selectionListener != null && event.getClickCount() == 2) { // get the selected node TreePath path = getSelectionPath(); if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode) { ClassSelectorClassNode node = (ClassSelectorClassNode) path.getLastPathComponent(); - listener.onSelectClass(node.getClassEntry()); + selectionListener.onSelectClass(node.getClassEntry()); } } } }); + if (gui != null) + { + final JTree tree = this; + + final DefaultTreeCellEditor editor = new DefaultTreeCellEditor(tree, + (DefaultTreeCellRenderer) tree.getCellRenderer()) + { + @Override public boolean isCellEditable(EventObject event) + { + return !(event instanceof MouseEvent) && super.isCellEditable(event); + } + }; + this.setCellEditor(editor); + editor.addCellEditorListener(new CellEditorListener() + { + @Override public void editingStopped(ChangeEvent e) + { + String data = editor.getCellEditorValue().toString(); + TreePath path = getSelectionPath(); + + Object realPath = path.getLastPathComponent(); + if (realPath != null && realPath instanceof DefaultMutableTreeNode && data != null) + { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) realPath; + TreeNode parentNode = node.getParent(); + if (parentNode == null) + return; + boolean allowEdit = true; + for (int i = 0; i < parentNode.getChildCount(); i++) + { + TreeNode childNode = parentNode.getChildAt(i); + if (childNode != null && childNode.toString().equals(data) && childNode != node) + { + allowEdit = false; + break; + } + } + if (allowEdit && renameSelectionListener != null) + { + Object prevData = node.getUserObject(); + Object objectData = node.getUserObject() instanceof ClassEntry ? new ClassEntry(((ClassEntry)prevData).getPackageName() + "/" + data) : data; + try + { + renameSelectionListener.onSelectionRename(node.getUserObject(), objectData, node); + node.setUserObject(objectData); + } catch (IllegalNameException ex) + { + JOptionPane.showOptionDialog(gui.getFrame(), ex.getMessage(), "Enigma - Error", JOptionPane.OK_OPTION, + JOptionPane.ERROR_MESSAGE, null, new String[] {"Ok"}, "OK"); + editor.cancelCellEditing(); + } + } + else + editor.cancelCellEditing(); + } + + } + + @Override public void editingCanceled(ChangeEvent e) + { + // NOP + } + }); + } // init defaults - this.listener = null; + this.selectionListener = null; + 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; } - public void setListener(ClassSelectionListener val) { - this.listener = val; + public void setRenameSelectionListener(RenameSelectionListener renameSelectionListener) + { + this.renameSelectionListener = renameSelectionListener; } public void setClasses(Collection classEntries) { @@ -105,12 +198,12 @@ public class ClassSelector extends JTree { } }); - // create the root node and the package nodes - DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + // create the rootNodes node and the package nodes + rootNodes = new DefaultMutableTreeNode(); for (String packageName : sortedPackageNames) { ClassSelectorPackageNode node = new ClassSelectorPackageNode(packageName); packages.put(packageName, node); - root.add(node); + rootNodes.add(node); } // put the classes into packages @@ -133,7 +226,7 @@ public class ClassSelector extends JTree { } // finally, update the tree control - setModel(new DefaultTreeModel(root)); + setModel(new DefaultTreeModel(rootNodes)); restoreExpanstionState(this, 0, state); } diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java index fd59a81..bc49a3f 100644 --- a/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/src/main/java/cuchaz/enigma/gui/Gui.java @@ -36,6 +36,7 @@ import de.sciss.syntaxpane.DefaultSyntaxKit; import javax.swing.*; import javax.swing.text.BadLocationException; import javax.swing.text.Highlighter; +import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; @@ -750,4 +751,22 @@ public class Gui { this.frame.validate(); this.frame.repaint(); } + + public void onPanelRename(Object prevData, Object data, DefaultMutableTreeNode node) throws IllegalNameException + { + // package rename + if (data instanceof String) + { + 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()); + this.controller.rename(new EntryReference<>(prevDataChild, prevDataChild.getName()), dataChild.getName()); + } + } + // class rename + else if (data instanceof ClassEntry) + this.controller.rename(new EntryReference<>((ClassEntry) prevData, ((ClassEntry) prevData).getName()), ((ClassEntry) data).getName()); + } } diff --git a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java index 60c6d8e..30902c4 100644 --- a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java +++ b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java @@ -35,7 +35,6 @@ import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.convert.ClassMatches; import cuchaz.enigma.convert.MemberMatches; -import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; import cuchaz.enigma.gui.highlight.DeobfuscatedHighlightPainter; import cuchaz.enigma.gui.highlight.ObfuscatedHighlightPainter; import cuchaz.enigma.mapping.ClassEntry; @@ -139,13 +138,8 @@ public class MemberMatchingGui { sourceTypePanel.add(button); } - m_sourceClasses = new ClassSelector(ClassSelector.DEOBF_CLASS_COMPARATOR); - m_sourceClasses.setListener(new ClassSelectionListener() { - @Override - public void onSelectClass(ClassEntry classEntry) { - setSourceClass(classEntry); - } - }); + m_sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR); + m_sourceClasses.setSelectionListener(this::setSourceClass); JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); classesPanel.add(sourceScroller); diff --git a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java index e083572..1c9dad4 100644 --- a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java +++ b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java @@ -20,6 +20,7 @@ public class ClassSelectorClassNode extends DefaultMutableTreeNode { public ClassSelectorClassNode(ClassEntry classEntry) { this.classEntry = classEntry; + this.setUserObject(classEntry); } public ClassEntry getClassEntry() { @@ -36,6 +37,18 @@ public class ClassSelectorClassNode extends DefaultMutableTreeNode { return other instanceof ClassSelectorClassNode && equals((ClassSelectorClassNode) other); } + @Override public void setUserObject(Object userObject) + { + String packageName = ""; + if (classEntry.getPackageName() != null) + packageName = classEntry.getPackageName() + "/"; + if (userObject instanceof String) + this.classEntry = new ClassEntry(packageName + userObject); + else if (userObject instanceof ClassEntry) + this.classEntry = (ClassEntry) userObject; + super.setUserObject(classEntry); + } + public boolean equals(ClassSelectorClassNode other) { return this.classEntry.equals(other.classEntry); } diff --git a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java index dfdc765..ee3009a 100644 --- a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java +++ b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java @@ -24,6 +24,13 @@ public class ClassSelectorPackageNode extends DefaultMutableTreeNode { return packageName; } + @Override public void setUserObject(Object userObject) + { + if (userObject instanceof String) + this.packageName = (String) userObject; + super.setUserObject(userObject); + } + @Override public String toString() { return this.packageName; diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java index bba7132..447c51a 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java @@ -17,8 +17,9 @@ public class PanelDeobf extends JPanel { public PanelDeobf(Gui gui) { this.gui = gui; - this.deobfClasses = new ClassSelector(ClassSelector.DEOBF_CLASS_COMPARATOR); - this.deobfClasses.setListener(gui::navigateTo); + this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR); + this.deobfClasses.setSelectionListener(gui::navigateTo); + this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); this.setLayout(new BorderLayout()); this.add(new JLabel("De-obfuscated Classes"), BorderLayout.NORTH); diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java index 94b384f..74772a5 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java @@ -28,8 +28,9 @@ public class PanelObf extends JPanel { return aname.compareTo(bname); }; - this.obfClasses = new ClassSelector(obfClassComparator); - this.obfClasses.setListener(gui::navigateTo); + this.obfClasses = new ClassSelector(gui, obfClassComparator); + this.obfClasses.setSelectionListener(gui::navigateTo); + this.obfClasses.setRenameSelectionListener(gui::onPanelRename); this.setLayout(new BorderLayout()); this.add(new JLabel("Obfuscated Classes"), BorderLayout.NORTH); -- cgit v1.2.3