diff options
Diffstat (limited to 'src/cuchaz/enigma/gui/ClassSelector.java')
| -rw-r--r-- | src/cuchaz/enigma/gui/ClassSelector.java | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java new file mode 100644 index 0000000..11333a9 --- /dev/null +++ b/src/cuchaz/enigma/gui/ClassSelector.java | |||
| @@ -0,0 +1,293 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2015 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Lesser General Public | ||
| 5 | * License v3.0 which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/lgpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.gui; | ||
| 12 | |||
| 13 | import java.awt.event.MouseAdapter; | ||
| 14 | import java.awt.event.MouseEvent; | ||
| 15 | import java.util.Collection; | ||
| 16 | import java.util.Collections; | ||
| 17 | import java.util.Comparator; | ||
| 18 | import java.util.Enumeration; | ||
| 19 | import java.util.List; | ||
| 20 | import java.util.Map; | ||
| 21 | |||
| 22 | import javax.swing.JTree; | ||
| 23 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 24 | import javax.swing.tree.DefaultTreeModel; | ||
| 25 | import javax.swing.tree.TreePath; | ||
| 26 | |||
| 27 | import com.google.common.collect.ArrayListMultimap; | ||
| 28 | import com.google.common.collect.Lists; | ||
| 29 | import com.google.common.collect.Maps; | ||
| 30 | import com.google.common.collect.Multimap; | ||
| 31 | |||
| 32 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 33 | |||
| 34 | public class ClassSelector extends JTree { | ||
| 35 | |||
| 36 | private static final long serialVersionUID = -7632046902384775977L; | ||
| 37 | |||
| 38 | public interface ClassSelectionListener { | ||
| 39 | void onSelectClass(ClassEntry classEntry); | ||
| 40 | } | ||
| 41 | |||
| 42 | public static Comparator<ClassEntry> ObfuscatedClassEntryComparator; | ||
| 43 | public static Comparator<ClassEntry> DeobfuscatedClassEntryComparator; | ||
| 44 | |||
| 45 | static { | ||
| 46 | ObfuscatedClassEntryComparator = new Comparator<ClassEntry>() { | ||
| 47 | @Override | ||
| 48 | public int compare(ClassEntry a, ClassEntry b) { | ||
| 49 | String aname = a.getName(); | ||
| 50 | String bname = a.getName(); | ||
| 51 | if (aname.length() != bname.length()) { | ||
| 52 | return aname.length() - bname.length(); | ||
| 53 | } | ||
| 54 | return aname.compareTo(bname); | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | |||
| 58 | DeobfuscatedClassEntryComparator = new Comparator<ClassEntry>() { | ||
| 59 | @Override | ||
| 60 | public int compare(ClassEntry a, ClassEntry b) { | ||
| 61 | if (a instanceof ScoredClassEntry && b instanceof ScoredClassEntry) { | ||
| 62 | return Float.compare( | ||
| 63 | ((ScoredClassEntry)b).getScore(), | ||
| 64 | ((ScoredClassEntry)a).getScore() | ||
| 65 | ); | ||
| 66 | } | ||
| 67 | return a.getName().compareTo(b.getName()); | ||
| 68 | } | ||
| 69 | }; | ||
| 70 | } | ||
| 71 | |||
| 72 | private ClassSelectionListener m_listener; | ||
| 73 | private Comparator<ClassEntry> m_comparator; | ||
| 74 | |||
| 75 | public ClassSelector(Comparator<ClassEntry> comparator) { | ||
| 76 | m_comparator = comparator; | ||
| 77 | |||
| 78 | // configure the tree control | ||
| 79 | setRootVisible(false); | ||
| 80 | setShowsRootHandles(false); | ||
| 81 | setModel(null); | ||
| 82 | |||
| 83 | // hook events | ||
| 84 | addMouseListener(new MouseAdapter() { | ||
| 85 | @Override | ||
| 86 | public void mouseClicked(MouseEvent event) { | ||
| 87 | if (m_listener != null && event.getClickCount() == 2) { | ||
| 88 | // get the selected node | ||
| 89 | TreePath path = getSelectionPath(); | ||
| 90 | if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode) { | ||
| 91 | ClassSelectorClassNode node = (ClassSelectorClassNode)path.getLastPathComponent(); | ||
| 92 | m_listener.onSelectClass(node.getClassEntry()); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
| 96 | }); | ||
| 97 | |||
| 98 | // init defaults | ||
| 99 | m_listener = null; | ||
| 100 | } | ||
| 101 | |||
| 102 | public void setListener(ClassSelectionListener val) { | ||
| 103 | m_listener = val; | ||
| 104 | } | ||
| 105 | |||
| 106 | public void setClasses(Collection<ClassEntry> classEntries) { | ||
| 107 | if (classEntries == null) { | ||
| 108 | setModel(null); | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | |||
| 112 | // build the package names | ||
| 113 | Map<String,ClassSelectorPackageNode> packages = Maps.newHashMap(); | ||
| 114 | for (ClassEntry classEntry : classEntries) { | ||
| 115 | packages.put(classEntry.getPackageName(), null); | ||
| 116 | } | ||
| 117 | |||
| 118 | // sort the packages | ||
| 119 | List<String> sortedPackageNames = Lists.newArrayList(packages.keySet()); | ||
| 120 | Collections.sort(sortedPackageNames, new Comparator<String>() { | ||
| 121 | @Override | ||
| 122 | public int compare(String a, String b) { | ||
| 123 | // I can never keep this rule straight when writing these damn things... | ||
| 124 | // a < b => -1, a == b => 0, a > b => +1 | ||
| 125 | |||
| 126 | String[] aparts = a.split("/"); | ||
| 127 | String[] bparts = b.split("/"); | ||
| 128 | for (int i = 0; true; i++) { | ||
| 129 | if (i >= aparts.length) { | ||
| 130 | return -1; | ||
| 131 | } else if (i >= bparts.length) { | ||
| 132 | return 1; | ||
| 133 | } | ||
| 134 | |||
| 135 | int result = aparts[i].compareTo(bparts[i]); | ||
| 136 | if (result != 0) { | ||
| 137 | return result; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | }); | ||
| 142 | |||
| 143 | // create the root node and the package nodes | ||
| 144 | DefaultMutableTreeNode root = new DefaultMutableTreeNode(); | ||
| 145 | for (String packageName : sortedPackageNames) { | ||
| 146 | ClassSelectorPackageNode node = new ClassSelectorPackageNode(packageName); | ||
| 147 | packages.put(packageName, node); | ||
| 148 | root.add(node); | ||
| 149 | } | ||
| 150 | |||
| 151 | // put the classes into packages | ||
| 152 | Multimap<String,ClassEntry> packagedClassEntries = ArrayListMultimap.create(); | ||
| 153 | for (ClassEntry classEntry : classEntries) { | ||
| 154 | packagedClassEntries.put(classEntry.getPackageName(), classEntry); | ||
| 155 | } | ||
| 156 | |||
| 157 | // build the class nodes | ||
| 158 | for (String packageName : packagedClassEntries.keySet()) { | ||
| 159 | // sort the class entries | ||
| 160 | List<ClassEntry> classEntriesInPackage = Lists.newArrayList(packagedClassEntries.get(packageName)); | ||
| 161 | Collections.sort(classEntriesInPackage, m_comparator); | ||
| 162 | |||
| 163 | // create the nodes in order | ||
| 164 | for (ClassEntry classEntry : classEntriesInPackage) { | ||
| 165 | ClassSelectorPackageNode node = packages.get(packageName); | ||
| 166 | node.add(new ClassSelectorClassNode(classEntry)); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | // finally, update the tree control | ||
| 171 | setModel(new DefaultTreeModel(root)); | ||
| 172 | } | ||
| 173 | |||
| 174 | public ClassEntry getSelectedClass() { | ||
| 175 | if (!isSelectionEmpty()) { | ||
| 176 | Object selectedNode = getSelectionPath().getLastPathComponent(); | ||
| 177 | if (selectedNode instanceof ClassSelectorClassNode) { | ||
| 178 | ClassSelectorClassNode classNode = (ClassSelectorClassNode)selectedNode; | ||
| 179 | return classNode.getClassEntry(); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | return null; | ||
| 183 | } | ||
| 184 | |||
| 185 | public String getSelectedPackage() { | ||
| 186 | if (!isSelectionEmpty()) { | ||
| 187 | Object selectedNode = getSelectionPath().getLastPathComponent(); | ||
| 188 | if (selectedNode instanceof ClassSelectorPackageNode) { | ||
| 189 | ClassSelectorPackageNode packageNode = (ClassSelectorPackageNode)selectedNode; | ||
| 190 | return packageNode.getPackageName(); | ||
| 191 | } else if (selectedNode instanceof ClassSelectorClassNode) { | ||
| 192 | ClassSelectorClassNode classNode = (ClassSelectorClassNode)selectedNode; | ||
| 193 | return classNode.getClassEntry().getPackageName(); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | return null; | ||
| 197 | } | ||
| 198 | |||
| 199 | public Iterable<ClassSelectorPackageNode> packageNodes() { | ||
| 200 | List<ClassSelectorPackageNode> nodes = Lists.newArrayList(); | ||
| 201 | DefaultMutableTreeNode root = (DefaultMutableTreeNode)getModel().getRoot(); | ||
| 202 | Enumeration<?> children = root.children(); | ||
| 203 | while (children.hasMoreElements()) { | ||
| 204 | ClassSelectorPackageNode packageNode = (ClassSelectorPackageNode)children.nextElement(); | ||
| 205 | nodes.add(packageNode); | ||
| 206 | } | ||
| 207 | return nodes; | ||
| 208 | } | ||
| 209 | |||
| 210 | public Iterable<ClassSelectorClassNode> classNodes(ClassSelectorPackageNode packageNode) { | ||
| 211 | List<ClassSelectorClassNode> nodes = Lists.newArrayList(); | ||
| 212 | Enumeration<?> children = packageNode.children(); | ||
| 213 | while (children.hasMoreElements()) { | ||
| 214 | ClassSelectorClassNode classNode = (ClassSelectorClassNode)children.nextElement(); | ||
| 215 | nodes.add(classNode); | ||
| 216 | } | ||
| 217 | return nodes; | ||
| 218 | } | ||
| 219 | |||
| 220 | public void expandPackage(String packageName) { | ||
| 221 | if (packageName == null) { | ||
| 222 | return; | ||
| 223 | } | ||
| 224 | for (ClassSelectorPackageNode packageNode : packageNodes()) { | ||
| 225 | if (packageNode.getPackageName().equals(packageName)) { | ||
| 226 | expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode})); | ||
| 227 | return; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | public void expandAll() { | ||
| 233 | for (ClassSelectorPackageNode packageNode : packageNodes()) { | ||
| 234 | expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode})); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | public ClassEntry getFirstClass() { | ||
| 239 | for (ClassSelectorPackageNode packageNode : packageNodes()) { | ||
| 240 | for (ClassSelectorClassNode classNode : classNodes(packageNode)) { | ||
| 241 | return classNode.getClassEntry(); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | return null; | ||
| 245 | } | ||
| 246 | |||
| 247 | public ClassSelectorPackageNode getPackageNode(ClassEntry entry) { | ||
| 248 | for (ClassSelectorPackageNode packageNode : packageNodes()) { | ||
| 249 | if (packageNode.getPackageName().equals(entry.getPackageName())) { | ||
| 250 | return packageNode; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | return null; | ||
| 254 | } | ||
| 255 | |||
| 256 | public ClassEntry getNextClass(ClassEntry entry) { | ||
| 257 | boolean foundIt = false; | ||
| 258 | for (ClassSelectorPackageNode packageNode : packageNodes()) { | ||
| 259 | if (!foundIt) { | ||
| 260 | // skip to the package with our target in it | ||
| 261 | if (packageNode.getPackageName().equals(entry.getPackageName())) { | ||
| 262 | for (ClassSelectorClassNode classNode : classNodes(packageNode)) { | ||
| 263 | if (!foundIt) { | ||
| 264 | if (classNode.getClassEntry().equals(entry)) { | ||
| 265 | foundIt = true; | ||
| 266 | } | ||
| 267 | } else { | ||
| 268 | // return the next class | ||
| 269 | return classNode.getClassEntry(); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | } | ||
| 273 | } else { | ||
| 274 | // return the next class | ||
| 275 | for (ClassSelectorClassNode classNode : classNodes(packageNode)) { | ||
| 276 | return classNode.getClassEntry(); | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | return null; | ||
| 281 | } | ||
| 282 | |||
| 283 | public void setSelectionClass(ClassEntry classEntry) { | ||
| 284 | expandPackage(classEntry.getPackageName()); | ||
| 285 | for (ClassSelectorPackageNode packageNode : packageNodes()) { | ||
| 286 | for (ClassSelectorClassNode classNode : classNodes(packageNode)) { | ||
| 287 | if (classNode.getClassEntry().equals(classEntry)) { | ||
| 288 | setSelectionPath(new TreePath(new Object[] {getModel().getRoot(), packageNode, classNode})); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | } | ||
| 293 | } | ||