package cuchaz.enigma.gui; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import cuchaz.enigma.mapping.ClassEntry; public class ClassSelector extends JTree { private static final long serialVersionUID = -7632046902384775977L; public interface ClassSelectionListener { void onSelectClass( ClassEntry classEntry ); } public static Comparator ObfuscatedClassEntryComparator; public static Comparator DeobfuscatedClassEntryComparator; static { ObfuscatedClassEntryComparator = new Comparator( ) { @Override public int compare( ClassEntry a, ClassEntry b ) { if( a.getName().length() != b.getName().length() ) { return a.getName().length() - b.getName().length(); } return a.getName().compareTo( b.getName() ); } }; DeobfuscatedClassEntryComparator = new Comparator( ) { @Override public int compare( ClassEntry a, ClassEntry b ) { return a.getName().compareTo( b.getName() ); } }; } private ClassSelectionListener m_listener; private Comparator m_comparator; public ClassSelector( Comparator comparator ) { m_comparator = comparator; // configure the tree control setRootVisible( false ); setShowsRootHandles( false ); setModel( null ); // hook events addMouseListener( new MouseAdapter() { @Override public void mouseClicked( MouseEvent event ) { if( m_listener != null && event.getClickCount() == 2 ) { // get the selected node TreePath path = getSelectionPath(); if( path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode ) { ClassSelectorClassNode node = (ClassSelectorClassNode)path.getLastPathComponent(); m_listener.onSelectClass( node.getClassEntry() ); } } } } ); // init defaults m_listener = null; } public void setListener( ClassSelectionListener val ) { m_listener = val; } public void setClasses( Collection classEntries ) { if( classEntries == null ) { setModel( null ); return; } // build the package names Map packages = Maps.newHashMap(); for( ClassEntry classEntry : classEntries ) { packages.put( classEntry.getPackageName(), null ); } // sort the packages List sortedPackageNames = Lists.newArrayList( packages.keySet() ); Collections.sort( sortedPackageNames, new Comparator( ) { @Override public int compare( String a, String b ) { // I can never keep this rule straight when writing these damn things... // a < b => -1, a == b => 0, a > b => +1 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 root node and the package nodes DefaultMutableTreeNode root = new DefaultMutableTreeNode(); for( String packageName : sortedPackageNames ) { ClassSelectorPackageNode node = new ClassSelectorPackageNode( packageName ); packages.put( packageName, node ); root.add( node ); } // put the classes into packages Multimap packagedClassEntries = ArrayListMultimap.create(); for( ClassEntry classEntry : classEntries ) { packagedClassEntries.put( classEntry.getPackageName(), classEntry ); } // build the class nodes for( String packageName : packagedClassEntries.keySet() ) { // sort the class entries List classEntriesInPackage = Lists.newArrayList( packagedClassEntries.get( packageName ) ); Collections.sort( classEntriesInPackage, m_comparator ); // create the nodes in order for( ClassEntry classEntry : classEntriesInPackage ) { ClassSelectorPackageNode node = packages.get( packageName ); node.add( new ClassSelectorClassNode( classEntry ) ); } } // finally, update the tree control setModel( new DefaultTreeModel( root ) ); } }