FileList

Here is a relatively simple Swing interface item that is much more useful for most games than a file chooser is. Basically, it scans an array of directories for files that end in an array of file extensions. Finally, the results are given in a JList, with an accept or cancel button. It also has the useful feature of being able to browse files that are both on your local file system and/or in your classpath. I haven’t actually tested the classpath part when coming from a JAR yet, but I believe it should work.

Easy to use and customizable. I’m making a pure LWJGL version in the near future.


import java.util.ArrayList;
import java.io.File;
import java.io.FilenameFilter;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListSelectionModel;

/**
 * A FileList is a window that contains a JList. The JList automatically fills with all files in
 * a list of given directories of a list of given extensions. Finally, the JList notifies a
 * FileListener of the final choice.
 * @author Eli Delventhal
 *
 */
public class FileList extends JFrame implements ActionListener
{
	private FileListener listener;
	private ArrayList<File> files;
	
	private JList list;
	private JButton confirm = new JButton("Select");
	private JButton cancel  = new JButton("Cancel");
	
	public FileList(FileListener listen, String[] directories, String[] extensions, boolean allowMultiple)
	{
		super("Select a File");
		listener = listen;
		
		list = createFileList(directories,extensions);
		if (allowMultiple)
			((DefaultListSelectionModel)list.getSelectionModel()).setSelectionMode(DefaultListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		else
			((DefaultListSelectionModel)list.getSelectionModel()).setSelectionMode(DefaultListSelectionModel.SINGLE_INTERVAL_SELECTION);
		
		Container cp = getContentPane();
		cp.setLayout(new BorderLayout());
		cp.add(new JScrollPane(list),BorderLayout.CENTER);
		JPanel p = new JPanel();
		p.setLayout(new GridLayout(1,2));
		p.add(cancel);	p.add(confirm);
		cp.add(p,BorderLayout.SOUTH);
		
		cancel.addActionListener(this);
		confirm.addActionListener(this);
		
		setSize(400,600);
		setVisible(true);
	}
	
	private JList createFileList(String[] directories, String[] extensions)
	{
		ArrayList<String> allFiles = new ArrayList<String>();
		
		//Browse through all directories.
		for (int i = 0; i < directories.length; i++)
		{
			//Try this directory as a "physical" file directory.
			try
			{
				String[] files = new File(directories[i]).list(new ExtensionFilter(extensions));
				for (int j = 0; j < files.length; j++)
				{
					if (!allFiles.contains(directories[i] + files[j]))
						allFiles.add(directories[i] + files[j]);
				}
			}
			catch (Exception e) {}
			
			//Try this directory as a classpath file directory.
			try
			{
				String[] files = new File(Thread.currentThread().getContextClassLoader().getResource(directories[i]).getFile()).list(new ExtensionFilter(extensions));
				for (int j = 0; j < files.length; j++)
				{
					if (!allFiles.contains(directories[i] + files[j]))
						allFiles.add(directories[i] + files[j]);
				}
			}
			catch (Exception e) {}
		}
		
		//Return all files that were found to be okay.
		return new JList(allFiles.toArray());
	}

	public void actionPerformed(ActionEvent e)
	{
		Object s = e.getSource();
		if (s == cancel)
			dispose();
		else if (s == confirm)
		{
			Object[] o = list.getSelectedValues();
			String[] files = new String[o.length];
			for (int i = 0; i < o.length; i++)
				files[i] = o[i].toString();
			listener.filesSelected(files);
			dispose();
		}
	}
	
	/**
	 * A simple file filter that allows files with any extensions from the list.
	 * Automatically disallows files with no extension.
	 * @author Eli Delventhal
	 *
	 */
	private class ExtensionFilter implements FilenameFilter
	{
		private String[] extensions;
		
		public ExtensionFilter(String[] ext)
		{
			extensions = ext;
		}
		
		public boolean accept(File directory, String name)
		{
			int lastPeriod = name.lastIndexOf(".");
			if (lastPeriod < 0 || lastPeriod >= name.length()-1)
				return false;
			
			String extension = name.substring(lastPeriod+1);
			for (int i = 0; i < extensions.length; i++)
				if (!extensions[i].equalsIgnoreCase(extension))
					return false;
			return true;
		}
		
	}
}


/**
 * The FileListener is a simple interface to be used with FileList.
 * @author Eli Delventhal
 *
 */
public interface FileListener
{
	public void filesSelected(String[] files);
}

Example usage:


public class PlanetPanel extends JPanel implements FileListener
...
new FileList(this,new String[]{"Systems/",FileManager.getResourceFolder().getAbsolutePath()+"/Systems/"},new String[]{"ps"},false);
...
/**
	 * Called when files have been selected. The first selected file will be loaded.
	 */
	public void filesSelected(String[] files)
	{
		if (files.length <= 0)
			return;
		
		ObjectInputStream is = null;
		
		//First, search for the file in local directories.
		try
		{
			is = new ObjectInputStream(Thread.currentThread().getContextClassLoader().getResourceAsStream(files[0]));
		}
		catch (Exception e)
		{
			//If the file isn't found, it must not be in the classpath, so search local directories.
			try
			{
				is = new ObjectInputStream(new FileInputStream(new File(files[0])));
			}
			catch (Exception ex)
			{
				//If it still isn't found, show an exception and then return.
				ex.printStackTrace();
				return;
			}
		}
		
		//Finally, read the input stream.
		try
		{
			x = (Double) is.readObject();
			y = (Double) is.readObject();
			METERS_PER_PIXEL = (Double) is.readObject();
			TIMESTEPS_PER_RENDER = (Integer) is.readObject();
			bodies = (ArrayList<Body>) is.readObject();
			is.close();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		repaint();
	}

I tested this out with a JAR, and you can’t use the File class to list the directory.

Anyone know how to list the contents of a directory within a JAR? I know how to do it via command line, but not within my code. Google searches reveal nothing.

Afaik you have to open the jar using JarInputStream and read out all the JarEntries and iterate over them yourself.

Blech, that’s what I figured. I don’t think that’s worth it - instead, I’ll include a place for the user to specify the exact locations in the classpath to look. After all, you should know exactly what goes into your JAR, so you shouldn’t need to check directory contents.