CRM
CRM

Reputation: 1349

How to list recently used files in JFileChooser Swing component

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

Answers (2)

MadProgrammer
MadProgrammer

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 ...

  • Create a JList and ListModel, set the JList as the JFileChoosers accessory (wrapping it in JScrollPane)
  • Each time you select a file, add it to a Set
  • Each time your go to open the JFileChooser, update the JList's model with the values from the Set (or back the model with the Set).
  • Each time the user selects a value from the list, you will need to change the JFileChoosers selectedFile property to reflect the change...

For more details, take a look at Providing an Accessory Component for more details...

Updated

Example

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

Deepanshu J bedi
Deepanshu J bedi

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.

This links may be helpful

example by peeskillet

Upvotes: 1

Related Questions