Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

altering JFileChooser behaviour : preventing "choose" on enter in file path JTextField

Greetings to Swing Pros, here's a good (I hope) question for you.

The below are the task requirements and possible solutions I see. I would like someone having had such a hardcore experience to share some thoughts about this.

This does not require coding or anything like that, I just need general advice as to which approach is more reliable regarding the fact I need to work with private symbols which reside in sun.swing and/or javax.swing.plaf packages.

The task is to modify/alter JFileChooser behaviour (just a little bit, actually).

  1. when the user presses enter in the file name JTextField, and the field contains a path to a dir, don't "select" the dir, but switch to it instead. Yes, the dialog is configured to accept directories, but we need to accept only clicks on the "Open" button, and (possibly) double-clicks in the file listing table.

  2. prevent user from selecting a dir/file with more than 1GB data via hitting enter in the file name text field

Here're couple of general solution options:

a. listen on the property-based changes that JFileChooser provides (which AFAICS are triggered after-the-fact and won't provide the degree of control we need here).

b. tinker with the javax.swing.plaf.basic.BasicFileChooserUI (via refrection, breaking the private-level encapsulation) and alter the reference to

private Action approveSelectionAction = new ApproveSelectionAction();

so that our custom action does the extra checks for 1 and 2. This approach links with plaf package and may fail in case this action is somehow overridden in some class below this UI class.

c. traverse the JFileChooser component hierarchy, find the JTextField (which apparently should occur only once in the component tree), decorate all the action listeners hanging on that JTextField with our custom checks. My debugging session shows that this JTextField is some anonymous subclass of JTextField living in the sun.swing.FilePane. This approach seems to be more OO-friendly, but there's a chance that for some OS this text field is absent, or some other JTextField is also present in the hierarchy.

Well, it seems that public JFileChooser API would not suffice to achieve that behaviour, while the other two options are either deep magic or unportable (long-term), or even both.

So, the question is: which approach would you choose and why?

like image 937
Anton Kraievyi Avatar asked Nov 20 '10 10:11

Anton Kraievyi


2 Answers

Regarding option2, you don't need to use reflection to customize the accept Action. You can just override the approveSelection() method. Something like:

JFileChooser chooser = new JFileChooser( new File(".") )
{
    public void approveSelection()
    {
        if (getSelectedFile().exists())
        {
            System.out.println("duplicate");
            return;
        }
        else
            super.approveSelection();
    }
};
like image 189
camickr Avatar answered Oct 20 '22 08:10

camickr


I recently encountered the same requirement, i.e., pressing Enter in the JTextField of a JFileChooser should cause the displayed dialog to traverse a directory instead of returning from the dialog. Only clicking on the Open button should cause the final selection.

The solution was fairly simple (at least for my application) and has two components to it (Pardon the messed up formatting. I'm new to this forum and I'm not sure why the code is not displaying correctly).

1 - Register an AWTListener to keep track of the last event type generated by the user

class MyChooser extends JFileChooser implements java.awt.AWTEventListener {

    ...
    MyChooser(){
        Toolkit.getDefaultToolkit().addAWTEventListener(this,
        AWTEvent.MOUSE_EVENT_MASK + AWTEvent.KEY_EVENT_MASK);
        ...

    }

    int lastEventId;

    public void eventDispatched(AWTEvent e) {
        lastEventId=e.getID();
    }
}

2 - Override the approveSelection() method of JFileChooser and check whether the approval request is a result of a mouse event (likely caused by the user clicking on the Open button) or a key event caused by the user pressing Enter. The 'lastEventId' variable provides access to this information. My own approveSelection then looks as follows:

public void approveSelection() {
    File f=getSelectedFile();
    if (f.exists() && isTraversable(f) && lastEventId ==
        KeyEvent.KEY_PRESSED) {
        setCurrentDirectory(f);
        return;
    }
    super.approveSelection(); } 
like image 43
perplexed Avatar answered Oct 20 '22 08:10

perplexed