Example native file dialog for OS X. Uses the Objective-C Cocoa Bridge (https://github.com/shannah/Java-Objective-C-Bridge) and Foxtrot (http://foxtrot.sourceforge.net/) for modal dialogs.
November 15, 2015 ยท View on GitHub
/*
- To change this template, choose Tools | Templates
- and open the template in the editor. */ package ca.weblite.cocoa.ui;
import ca.weblite.objc.NSObject; import ca.weblite.objc.Proxy; import java.awt.FileDialog; import static ca.weblite.objc.RuntimeUtils.msg; import static ca.weblite.objc.RuntimeUtils.msgString; import static ca.weblite.objc.util.CocoaUtils.dispatch_sync; import static ca.weblite.objc.RuntimeUtils.sel; import com.sun.jna.Pointer; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.JFrame;
/**
-
A wrapper around NSSavePanel and NSOpenPanel with some methods similar to java.awt.FileDialog.
-
This class includes wrappers for most settings of both NSSavePanel and NSOpen panel so that
-
you have full flexibility (e.g. select directories only, files only, force a certain extension,
-
allow user to add folders, show hidden files, etc...
-
NOTE: Don't run the NativeFileDialog on the Swing EDT as it will cause a deadlock. Check out the
-
example_directory_dialog.java snippet for an example using FoxTrot to do a modal dialog in a safe way.
-
Example Save Panel
-
-
NativeFileDialog dlg = new NativeFileDialog("Save as...", FileDialog.SAVE); dlg.setMessage("Will save only as .txt file"); dlg.setExtensionHidden(true); dlg.setAllowedFileTypes(Arrays.asList("txt")); dlg.setVisible(true); // this is modal
String f = dlg.getFile(); if ( f == null ){ return; } File file = new File(f); saveFile(file);
-
Example Open Panel
-
-
NativeFileDialog dlg = new NativeFileDialog("Select file to open", FileDialog.LOAD); dlg.setVisible(true); // this is modal. String f = dlg.getFile(); if ( f != null ){ openFile(new File(f)); }
-
@author shannah
-
@see java.awt.FileDialog API docs */ public class NativeFileDialog extends NSObject {
/**
- Reference to the Obj-C NSOpenPanel or NSSavePanel class. */ private Proxy peer;
/**
- Either FileDialog.LOAD or FileDialog.SAVE */ private int mode;
/**
-
Creates a new file dialog with the specified title and mode.
-
@param title The title for the dialog.
-
@param mode Whether to be an open panel or save panel. Either java.awt.FileDialog.SAVE
-
or java.awt.FileDialog.LOAD */ public NativeFileDialog(final String title, final int mode){ super("NSObject"); this.mode = mode; dispatch_sync(new Runnable(){
@Override public void run() { if (mode == FileDialog.LOAD ){ peer = getClient().sendProxy("NSOpenPanel", "openPanel"); } else { peer = getClient().sendProxy("NSSavePanel", "savePanel"); } peer.send("setTitle:", title); peer.send("retain"); }}); }
/**
-
Sets a given selector with a string value on the main thread.
-
@param selector An objective-c selector on the NSSavePanel object. e.g. "setTitle:"
-
@param value The value to set the selector. */ private void set(final String selector, final String value){ dispatch_sync(new Runnable(){
@Override public void run() { System.out.println(peer.getPeer()); if ( peer.getPeer().equals(Pointer.NULL)){ throw new RuntimeException("The peer is null"); } System.out.println("Before send "+selector+" : "+value); peer.send(sel(selector), value); System.out.println("After send"); }}); }
/**
-
Sets a given selector with an int value on the main thread.
-
@param selector An objective-c selector on the NSSavePanel object. e.g. "setShowsHiddenFiles:"
-
@param value The int value to set. */ private void set(final String selector, final int value){ dispatch_sync(new Runnable(){
@Override public void run() { System.out.println("About to send to selector: "+selector); peer.send(selector, value); }}); }
/**
-
Returns the result of a selector on the main thread for the NSSavePanel
-
object.
-
@param selector The selector to be run. e.g. "title".
-
@return The result of calling the given selector on the NSSavePanel object. */ private String getString(final String selector){ final String[] out = new String[1]; dispatch_sync(new Runnable(){
@Override public void run() { out[0] = peer.sendString(selector); }}); return out[0]; }
/**
-
Returns the result of running a selector on the NSSavePanel on the main thread.
-
@param selector The selector to be run. E.g. "showsHiddenFiles"
-
@return The int result. */ private int getI(final String selector){ final int[] out = new int[1]; dispatch_sync(new Runnable(){
@Override public void run() { out[0] = peer.sendInt(sel(selector)); }}); return out[0]; }
/**
- Sets title of the dialog.
- @param title The title.
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html */ public void setTitle(String title){ set("setTitle:", title); }
/**
- Gets the title of the dialog.
- @return The title
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html */ public String getTitle(){ return getString("title"); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param prompt */ public void setPrompt(String prompt ){ set("setPrompt:", prompt); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param label */ public void setNameFieldLabel(String label){ set("setNameFieldLabel:", label); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public String getNameFieldLabel(){ return getString("nameFieldLabel"); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param message */ public void setMessage(String message){ set("setMessage:", message); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public String getMessage(){ return getString("message"); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public String getPrompt(){ return getString("prompt"); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public boolean canCreateDirectories(){ return getI("canCreateDirectories") != 0; }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param can */ public void setCanCreateDirectories(boolean can){ set("setCanCreateDirectories:", can?1:0); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public boolean showsHiddenFiles(){ return getI("showsHiddenFiles") != 0; }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param shows */ public void setShowsHiddenFiles(boolean shows){ set("setShowsHiddenFiles:", shows?1:0); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public boolean isExtensionHidden(){ return getI("isExtensionHidden")!=0; }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param hidden */ public void setExtensionHidden(boolean hidden){ set("setExtensionHidden:", hidden?1:0); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public boolean canSelectHiddenExtension(){ return getI("canSelectHiddenExtension")!=0; }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param sel */ public void setCanSelectHiddenExtension(boolean sel){ set("setCanSelectHiddenExtension:", sel?1:0); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param val */ public void setNameFieldStringValue(String val){ set("setNameFieldStringValue:", val); }
/**
-
@return */ public List
getAllowedFileTypes(){ final List out = new ArrayList (); dispatch_sync(new Runnable(){ @Override public void run() { Proxy types = peer.sendProxy("allowedFileTypes"); int size = types.getInt("count"); for ( int i=0; i<size; i++){ String nex = types.sendString("objectAtIndex:", i); out.add(nex); } }});
return out; }
/**
-
@param types */ public void setAllowedFileTypes(final List
types){ dispatch_sync(new Runnable(){ @Override public void run() { Proxy mutableArray = getClient().sendProxy("NSMutableArray", "arrayWithCapacity:", types.size()); for (String type: types){ mutableArray.send("addObject:", type); } peer.send("setAllowedFileTypes:", mutableArray); //mutableArray.send("release"); }}); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public boolean allowsOtherFileTypes(){ return getI("allowsOtherFileTypes")!=0; }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param allowed */ public void setAllowsOtherFileTypes(boolean allowed){ set("setAllowsOtherFileTypes:", allowed?1:0); }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @return */ public boolean getTreatsFilePackagesAsDirectories(){ return getI("treatsFilePackagesAsDirectories")!=0; }
/**
- @see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nssavepanel_Class/Reference/Reference.html
- @param treat */ public void setTreatsFilePackagesAsDirectories(boolean treat){ set("setTreatsFilePackagesAsDirectories:", treat?1:0); }
/**
-
Returns the path to the directory that was selected.
-
@return */ public String getDirectory(){ final String[] out = new String[1]; dispatch_sync(new Runnable(){
@Override public void run() { Proxy dirUrl = peer.sendProxy("directoryURL"); if ( dirUrl.getPeer().equals(Pointer.NULL)){ out[0] = null; } else { out[0] = dirUrl.sendString("path"); } }}); return out[0]; }
/**
-
Gets the path to the file that was selected.
-
@return */ public String getFile(){
final String[] out = new String[1]; dispatch_sync(new Runnable(){
@Override public void run() { Proxy fileUrl = peer.sendProxy("URL"); System.out.println("File URL :"+fileUrl.getPeer()); if ( fileUrl == null || fileUrl.getPeer().equals(Pointer.NULL)){ out[0] = null; } else { System.out.println("Getting path for file URL "+fileUrl.getPeer()); long p = msg(fileUrl.getPeer(), "path"); System.out.println("Result of path is "+p); String path = msgString(new Pointer(p), "UTF8String" ); System.out.println("Actual path is "+path); out[0] = fileUrl.sendString("path"); } }}); return out[0];
}
/**
-
Returns an array of files that were selected by the user.
-
@return */ public File[] getFiles(){ final List
out = new ArrayList (); dispatch_sync(new Runnable(){ @Override public void run() { if ( mode == FileDialog.LOAD ){ Proxy nsArray = peer.getProxy("URLs"); if ( !nsArray.getPeer().equals(Pointer.NULL)){ int size = nsArray.sendInt("count"); for ( int i=0; i<size; i++){ Proxy url = nsArray.sendProxy("objectAtIndex:", i); String path = url.sendString("path"); out.add(new File(path)); } } } }});
return out.toArray(new File[0]);
}
/**
- Returns the mode of this dialog.
- @return either FileDialog.LOAD or FileDialog.SAVE */ public int getMode(){ return mode; }
/**
- Returns true if the dialog allows multiple selection.
- @return */ public boolean isMultipleMode(){ return getI("allowsMultipleSelection")!=0; }
/**
- Sets whether the dialog allows the user to select multiple files or not.
- @param enable */ public void setMultipleMode(boolean enable){ set("setAllowsMultipleSelection:", enable?1:0); }
/**
- Returns whether the user can select files in this dialog.
- @return */ public boolean canChooseFiles(){ return getI("canChooseFiles")!=0; }
/**
- Sets whether the user can select files in this dialog.
- @param can */ public void setCanChooseFiles(boolean can){ set("setCanChooseFiles:", can?1:0); }
public boolean getCanChooseDirectories(){ return getI("canChooseDirectories")!=0; }
public void setCanChooseDirectories(boolean can){ set("setCanChooseDirectories:", can?1:0); }
public boolean getResolvesAliases(){ return getI("resolvesAliases")!=0; }
public void setResolvesAliases(boolean resolves){ set("setResolvesAliases:", resolves?1:0); }
/**
-
Sets the directory that the dialog displays.
-
@param dir */ public void setDirectory(final String dir){ dispatch_sync(new Runnable(){
@Override public void run() { Proxy url = getClient().sendProxy("NSURL", "fileURLWithPath:isDirectory:", dir, 1); peer.send("setDirectoryURL:", url.getPeer()); }}); }
/**
- Unsupported
- @param file */ public void setFile(String file){ throw new UnsupportedOperationException("setFile() notimplemented"); }
/**
- Unsupported
- @param mode */ public void setMode(int mode){ throw new UnsupportedOperationException("Can't set mode after initialization"); }
@Override protected void finalize() throws Throwable { super.finalize(); }
public void setVisible(boolean visible){ dispatch_sync(new Runnable(){
@Override public void run() { peer.send("runModal"); } });}
public static void main(String[] args){ NativeFileDialog dlg = new NativeFileDialog("Foo", FileDialog.SAVE); //dlg.peer.send("runModal"); //System.out.println("Get title: "+dlg.getTitle()); dlg.setTitle("bar"); dlg.setPrompt("The prompt"); dlg.setMessage("The message"); dlg.setCanCreateDirectories(true); dlg.setAllowedFileTypes(Arrays.asList("zip"));
dlg.setVisible(true); System.out.println(dlg.getFile()); System.out.println("done");}
}