I myself am far from being a master of the Java Native Interface (JNI), since I only started doing
my first JNI a few days ago. The problem we were having is that there is no way in Java to get some
native behavior on OS X. For example, the closest to native you can get with Open/Save file dialogs
is what you get from java.awt.FileDialog
, which isn't very much.
Since we're developing in Swing it is key that if we do anything, it should be wrapped up in a neat
little package that mimics existing Swing components. Not only that, but we want the behavior of any
wrapper classes to be the exact same, or very similar to, the corresponding JComponent
. Although
it's far from being ready for public release, I currently have a pretty solid JNI library for the
open/save dialogs in OS X. It's all wrapped up neatly in CarbonFileChooser
, an extension to
JFileChooser
.
One issue that arose, at least for OS X, is that there are various threads that have to run
independently: the AWT/Swing thread, and the AppKit thread. Hence, when one makes a native call that
is going to be doing some GUI stuff or event-oriented callbacks to the AWT/Swing thread, one has to
forward things along to the AppKit thread. This can be done via the performSelectorOnMainThread
method. To achieve modality, I use the following code:
1public int showSaveDialog(Component parent) {
2 dialogOpen = true;
3 result = CANCEL_OPTION;
4 cc_showSaveDialog(parent);
5 while(dialogOpen) {
6 try {
7 Thread.sleep(100);
8 } catch(InterruptedException e) { }
9 }
10
11 return result;
12}
What happens is that when the dialog is disposed, JNI calls are executed to set the dialogOpen
variable to false, breaking the loop. I've been debating trying out wait()
and using JNI to wake
up the object instead, but for now the above code gets the job done.
Eventually I'm going to release this code library to the public so that anyone can use it, and
eventually I'll open-source it (when I'm too lazy to keep maintaining it). The beauty of this, if
one is using Swing, is that you really don't change your code at all. Just create the
CarbonFileChooser
class and you're good to go. Right now things are simple, so just some basic
things can be done. You can do the following:
Set the initial directory
Add choosable filters, set the initial file filter, and get the chosen file filter once the dialog is disposed
Get the selected file to open/save
And some things left to do:
Multiple file selection and retrieval
Show no filters if the "All Files" filter is the only one
Setting the initial file name for save dialogs
Update dialog to unselect files, as necessary, when filter changes