Reputation: 1349
I am using javax.swing.JFileChooser swing component in my Java Project for opening file by dialog. How to list recently used files for selection in JFileChooser. Everytime I am going inside the directory and selecting file which is time-consuming.
How do I list last few recently used files in the component itself so that we dont need to navigate through the directories again and again to select a file?
Upvotes: 2
Views: 1849
Reputation: 347194
JFileChooser
allows you to supply a accessory
Component
which is added to the JFileChooser
component, on the right side under Windows.
What you could do is ...
JList
and ListModel
, set the JList
as the JFileChoosers
accessory
(wrapping it in JScrollPane
)Set
JFileChooser
, update the JList
's model with the values from the Set
(or back the model with the Set
).JFileChoosers
selectedFile
property to reflect the change...For more details, take a look at Providing an Accessory Component for more details...
Updated
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileSystemView;
public class TestFileChooser {
public static void main(String[] args) {
new TestFileChooser();
}
public TestFileChooser() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JFileChooser fc;
private RectentFileList rectentFileList;
public TestPane() {
setLayout(new GridBagLayout());
JButton chooser = new JButton("Choose");
chooser.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (fc == null) {
fc = new JFileChooser();
rectentFileList = new RectentFileList(fc);
fc.setAccessory(rectentFileList);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
}
switch (fc.showOpenDialog(TestPane.this)) {
case JOptionPane.OK_OPTION:
File file = fc.getSelectedFile();
rectentFileList.add(file);
break;
}
}
});
add(chooser);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class RectentFileList extends JPanel {
private final JList<File> list;
private final FileListModel listModel;
private final JFileChooser fileChooser;
public RectentFileList(JFileChooser chooser) {
fileChooser = chooser;
listModel = new FileListModel();
list = new JList<>(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(new FileListCellRenderer());
setLayout(new BorderLayout());
add(new JScrollPane(list));
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
File file = list.getSelectedValue();
// You might like to check to see if the file still exists...
fileChooser.setSelectedFile(file);
}
}
});
}
public void clearList() {
listModel.clear();
}
public void add(File file) {
listModel.add(file);
}
public class FileListModel extends AbstractListModel<File> {
private List<File> files;
public FileListModel() {
files = new ArrayList<>();
}
public void add(File file) {
if (!files.contains(file)) {
if (files.isEmpty()) {
files.add(file);
} else {
files.add(0, file);
}
fireIntervalAdded(this, 0, 0);
}
}
public void clear() {
int size = files.size() - 1;
if (size >= 0) {
files.clear();
fireIntervalRemoved(this, 0, size);
}
}
@Override
public int getSize() {
return files.size();
}
@Override
public File getElementAt(int index) {
return files.get(index);
}
}
public class FileListCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof File) {
File file = (File) value;
Icon ico = FileSystemView.getFileSystemView().getSystemIcon(file);
setIcon(ico);
setToolTipText(file.getParent());
setText(file.getName());
}
return this;
}
}
}
}
The question of persistence is broad question and will come down to your personal needs, for example, you could just dump the list of files out to a flat file, this is probably the simplest solution, as it means you can simply read the file from start to finish and know you have the entire contents. Also, writing out the file again will override any previous values, making it easy to manage.
Other solutions might require to provide a "count" property, which you would then suffix to a known key to list the values, which would require to manually remove the old values when you update the details. You could also try using a delimiter to save all the values as a single value in the persistence store, but this wrought with issues of picking a delimiter that won't be used within the file names (the path separator might do :D)
Take a look at How can I save the state of my program and then load it? for some more ideas...
Updated
After a little thought, you could use the Preferences
API to store the list of files using a single key by using the File.pathSeparator
, as this should be unique and not used by a file name/path.
For example, you could save the list using something like...
StringBuilder sb = new StringBuilder(128);
for (int index = 0; index < listModel.getSize(); index++) {
File file = listModel.getElementAt(index);
if (sb.length() > 0) {
sb.append(File.pathSeparator);
}
sb.append(file.getPath());
}
System.out.println(sb.toString());
Preferences p = Preferences.userNodeForPackage(TestFileChooser.class);
p.put("RectentFileList.fileList", sb.toString());
And load it again using something like...
Preferences p = Preferences.userNodeForPackage(TestFileChooser.class);
String listOfFiles = p.get("RectentFileList.fileList", null);
if (listOfFiles != null) {
String[] files = listOfFiles.split(File.pathSeparator);
for (String fileRef : files) {
File file = new File(fileRef);
if (file.exists()) {
add(file);
}
}
}
Upvotes: 4
Reputation: 1530
Use setSelectedFile(File file) method of JFileChooser.
The doc says:
public void setSelectedFile(File file)
Sets the selected file. If the file's parent directory is not the current directory, changes the current directory to be the file's parent directory.
Upvotes: 1