I am implementing a Java application using the Swing GUI framework on macOS. When using the system look and feel and a screen menu bar, Swing automatically inserts a search field called Spotlight for Help into the first menu labelled "Help" of the menu bar of a frame:
System.setProperty("apple.laf.useScreenMenuBar", "true");
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
JFrame frame = new JFrame();
JMenuBar menuBar = new JMenuBar();
JMenu helpMenu = new JMenu("Help");
menuBar.add(helpMenu);
frame.setJMenuBar(menuBar);
As my application is localized, the English string "Help" is different in other locales (e.g. "Aide" in French). But in those cases Swing does not insert Spotlight for Help since the string is different:
Solution
Bundle the .class files and resources (image, sound, video, localization files, etc.) of your application in a .jar file with Oracle's Java Archive.
Bundle your .jar file in an .app directory with Oracle's AppBundler (for Java 7+, which replaces the old Apple's JarBundler for Java 6).
Add to the .app directory the Contents/Resources/<locale>.lproj directories for each locale that should be supported by your application (you can let the locale directories empty since the localization files can be already in the .jar file).
Launch your application (double-click on the application icon in Finder or type open <application>.app in Terminal).
The search field Spotlight for Help will appear.
Explanation
I'm going to make a guess and it's that you're executing the .class files directly (from an IDE, for instance) or the .jar file, because from what I know this should be working.
Although what most sources say, Swing is deeply rooted on system calls and thus relies on the OS for many features, like in this case. Ideally, this should be covered by the method setHelpMenu(JMenu) but as you'll notice this has never been implemented.
If you check first, you'll notice that there's no extra component added in your JMenuBar and you have no control over that. If you try using AWT's MenuBar instead you'll see the behavior is exactly the same although, insterestingly enough, the method setHelpMenu(Menu) it is really implemented but doesn't add the search field if the menu is named something different from "Help".
At this point I found a workaround and it's setting the menu label to "Help" and once displayed (don't use ComponentListener.componentShown(ComponentEvent), this won't work, use AncestorListener.ancestorAdded(AncestorEvent)) changing the menu label to the localized one. This will add the search field to the help menu. However the search field will in English, with the label "Search".
Checking the API, it's more than clear that in Swing this feature is not implemented and fully relies on AWT. AWT on the other hand has partly implemented the native calls to the OS, but it's not wired to be invokable. Reaching this point and knowing that the search field does appear in our application and that in other ones running in Java it's properly localized lets us hint that this is a trait of the OS itself (I might be wrong at this point and it's really AWT doing the dirty job, but wasn't able to find any piece of code that does it directly, although in Objective C you can define any).
Reading the documentation about how to localize a Java application in MacOS, we note that:
it's a requirement that the application be bundled in an .app directory and contain the Contents/Resources/<os-locale>.lproj directory, so that the OS recognizes the OS locale as supported by the application, and consequently expects a menu labeled with the OS-localized "Help" string in order to add the OS-localized search field to that menu;
otherwise, the OS treats the application as en_US localized, and consequently expects a menu labeled with the en_US-localized "Help" string in order to add the en_US-localized search field to that menu.
Now you can type open <application>.app in Terminal and your application will be launched with the OS-localized search field added to the help menu.
Note that Apple has its own mechanism for forcing the application to use another locale than the OS locale, and it's using the -AppleLanguages option (open <application>.app --args -AppleLanguages "(<locale>)"). The Language Switcher utility does the same under the hood. Again, the appropriate Contents/Resources/<locale>.lproj directory should exist, otherwise the OS will treat the application as en_US localized.
How you make an .app directory from the .class files and resources (image, sound, video, localization files, etc.) of your application is beyond the scope of this question because it varies depending on the platform you're using, but Oracle provides the Java Archive (to make the intermediary .jar file) and AppBundler (to make the .app directory) utilities.
Screenshot
The OS is localized in Spanish in this screenshot but the application is localized in French, because it's been launched with the -AppleLanguages "(fr)" option.
I have just found out another way. No need to add empty Contents/Resources/<locale>.lproj directories in the .app directory, just adding these two lines (key-value pair) in the Contents/Info.plist file of the .app directory works:
<key>CFBundleAllowMixedLocalizations</key>
<true />
And the new way to make an .app bundle is to use Oracle's JavaPackager command-line utility, which is part of the J.D.K. It generates an .app directory with a Contents/Info.plist that has the above two lines by default (no need to pass the key-value pair as an option of javapackager in the command-line). And forcing another locale with the open <application>.app --args -AppleLanguages "(<locale>)" command really works with the <application>.app directory generated by Oracle's JavaPackager, contrary to the one generated by Oracle's AppBundler.
Related
Firstly, I am aware that my question may take some flak because JavaFX has its own FileChooser (that is largely superior/preferable to Swing's JFileChooser) and that mixing FX and Swing should be dissuaded. However - I will explain the functionality I'm trying to build and I am very open to suggestions on how else get there - if indeed I'm going in the wrong direction.
So firstly - the main application is built in JavaFX and is designed to calculate and archive parameters for biological samples. The primary observable is a tabPane wherein a new instance of a tab is generated for each new sample. As well as calculating and archive parameters for each sample, the user is also be able to store any type of data file in relation to each sample within the project. This is just for archiving - I do not plan to have in depth interaction with these files. Now, I come from a UNIX background and would very much like a sensible data structure to my "Project Folder" which can be sharable, externally editable and human-readable. In this regard, my overall idea was to make my saved output as follows:
A root folder (i.e. not a bespoke file format - just a classic folder)
Within the root folder:
1. A main XML file detailing specifics of the project
2. A second tier of folders - one for each tab of the project
Within the sample-specific folders:
1. An XML file detailing specifics of the sample
2. All the imported files/data in relation to this sample
Now - that all being said, I have the open/save functionality I'm aiming for functioning with Swing's JFileChooser. With a customised FileView class underpinning the JFileChooser, I can define a specific type of folder (both in relation to a pseudo-extension and its internal files and their content) as untraversable, give it a specific icon and then open it with the filechooser, in effect, as if it were a true file.
However, with the JavaFX Choosers, this becomes complicated. Because the ShowSaveDialog method does not exist for DirectoryChooser, from having to use FileChooser.ShowSaveDialog(), you can easily incorrectly save a folder within an already existing project (instead of rewriting it) - as, at least in OSX, this is poorly highlighted in the system file explorer. A further pain is that in selecting a folder - it does not populate the savename input box, the explorer simply descends into that directory.
Likewise - in opening a folder, the FileChooser.ShowOpenDialog() is clearly inappropriate. Using DirectoryChooser.ShowDialog() here is much more palatable, however the distinction between normal folders and project related folders (i.e. setting them untraversable and defining an icon) is something still better handled in Swing's JFileChooser.
Therefore, is anyone able to recommend how I can open a JFileChooser from within my FX app? I've tried running JFileChooser from a SwingNode, but I don't think I've implemented it correctly.
Dialog SaveDialog = new Dialog();
SaveDialog.setTitle("Save Project");
SaveDialog.setResizable(true);
SwingNode swingnode = new SwingNode();
JFileChooser SaveChooser = new JFileChooser();
SaveChooser.setAcceptAllFileFilterUsed(false);
FileNameExtensionFilter filter = new FileNameExtensionFilter(".prot projects", "*.prot");
SaveChooser.setFileFilter(filter);
SaveChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
FileView view = new main.COBFileView();
SaveChooser.setFileView(view);
swingnode.setContent(SaveChooser);
SaveDialog.getDialogPane().setContent(swingnode);
Window window = SaveDialog.getDialogPane().getScene().getWindow();
window.setOnCloseRequest(event -> window.hide());
SaveDialog.showAndWait();
Or, on the other hand how I can replicate this functionality using FX?
Any help would be greatly appreciated!
What is the difference between symbolic links and shortcuts?
As I was reading Oracle's Documentation on java.nio.file package, there I came to know about symbolic links. At first, I thought they are talking about shortcuts because at first they both appeared the same to me. But later I realised that I am kind of assuming this without a proof so i googled it and found some links about the differences between the two. But I couldn't get a clear view of what these actually are as the answers were not that good. I hope I can get an explanation here!
A symbolic link is a special file which references another path on disk. If an application opens this file (or includes it in a path), the operating system will silently follow the link.
For instance, assume you have a symbolic link l which points to a directory d with a file file in it. Observe:
$ ls d/
file
$ ls l/
file
$ touch l/file2 # Create a new file in the path under l
$ ls d/
file file2
Symbolic links (symlinks) are a feature of the filesystem part of the operating system. They can be used by any application; applications that do want to treat symlinks differently (such as backup programs, which must not blindly follow symlinks lest the number of files becomes infinite) need to take special precaution to do so.
In contrast, a shortcut is a regular file which is rendered differently by the user interface(UI). A shortcut file also contains the desired target path, but can contain additional information, such as an icon, command-line arguments, instructions to the UI to run the destination as another user, categorization of the destination, translation information and the like. For an application, a shortcut is a regular file whose contents describe the shortcut. For instance, if you open a .desktop file with an editor, you'll see information like
Icon=libreoffice-calc
Exec=libreoffice --calc %U
GenericName=Spreadsheet
GenericName[da]=Regneark
You should generally use shortcuts if you want to add an entry to the user interface (typically the graphical parts). Shortcuts allow you extended customization - for instance, Danish users will see Regneark, and English users Spreadsheet in the above example.
If, on the other hand, you want the alias to be visible to all applications, go for a symlink instead. For instance, you could have a legacy name of a file that some applications expect, or one application that can do multiple things, or the current version of a project directory.
Note that some systems do not support symlinks, and some have no use for shortcuts. If there is no graphical interface present (for instance a home router without a monitor attached), shortcuts would not be useful. On the other hand, symlinks require support by the filesystem (FAT has none) as well as the operating system (DOS/old versions of Windows lack support).
I am displaying a list of files; i.e. xls, doc, pdf, odt etc., in my Java application (Eclipse RCP). When the user clicks on the file, I want to launch the appropriate (according to what the OS thinks) native application, just like it happens in Windows Explorer or the Finder.
And while I am here: It would be nice to also display the same icons that Finder or Explorer use for the different file types.
Is there a library or Eclipse plugin for this?
What you want is java.awt.Desktop:
Desktop.getDesktop().open( file );
I have found an API in Eclipse's SWT now that seems to do the trick:
org.eclipse.swt.program.Program "provides access to facilities for discovering operating system specific aspects of external program launching."
It has methods to find the program for a given file extension, get the program's icon, and even launch the program.
Sounds like you're after the Java Activation Framework ("JAF"). This API lets you determine what files are and what actions you can do on them. Or alternatively the Java Desktop Integration Component ("JDIC"). JDIC allows you to create and no doubt query file associations.
Both projects seem to be in a semi-abandoned state howeer (sigh). But that's par for the course for Sun these days. Only other thing I know of is some Windows specific third party library that's based on JNI called Winpack. It does a bunch of other things too.
You can get the associated icon using the FileSystemView class (Java 1.4+).
I am creating a java swing application and I need to set the my program as the default program for the file extension .mcsd (MIME type text/mcsd). This must work on windows, and it would be nice if it worked on OS X/Linux as well. I am somewhat new to java (3 or 4 months) so please don't bombard me with all kinds of expert talk.
I have seen associating a custom file extension with java app in windows, but I would prefer not to use the Java Web Start. If possible, I would also like to know how to set the icon of that file type. I have found exe4j as a way of creating the .exe and plan to use it, but if is not the best tool for convertinf to an exe or someone knows something better feel free to tell me. Another thing: I need to be able to get the data from this file after the program has opened.
So my question is: how do I do this?
Deploy the app. with Java Web Start:
JWS provides many appealing features including, but not limited to, splash screens, desktop integration, file associations, automatic update ..
See the file services demo. for an example of a JNLP that declares an interest in the .zzz file type.
This is how the association is declared in the JNLP:
<association
extensions="zzz"
mime-type="text/sleepytime" />
JWS is supplied by Oracle and works on Windows, *nix & OS X.
..but I would prefer not to use the Java Web Start. Because I would like to have a native installer that just installs the program, without opening a web page or anything. If that's not how (web start) works, then I'm happy to use it.
JWS works over the web or a network. But if you can invoke the opening of an URL (to the JNLP) from the desktop, there does not need to be any browser opened.
Would I do that using openConnection() on a URL object?
I would use the Desktop or BasicService API.
Desktop.getDesktop().browse(uri);
boolean result = basicService.showDocument(url);
As noted in the BasicService demo.
In Java 6+, a call to show another web start launch file (e.g. BasicService.showDocument(another.jnlp)) will be handed directly to JavaWS, with no browser window appearing.
I expect this has always been true of the Desktop API, given the JWS client is the default consumer for that file type.
I want to know how to make a java program that can be used to open stuff up. Ex: notepad++, win zip.... Do I have convert the jar to .exe first? Also, does the file chosen get passed in to String[] args?
By the way, I know that it works with cmd but thats not what I'm asking.
Depends on the OS. Under windows, you need to attach some details into the registry.
Have a look at the 3rd answer in Utilising a file association in a Java application for an example?
You could also have a look at http://www.rgagnon.com/javadetails/java-0592.html
UPDATE
Also, when the OS executes the program, you should receive the file as a command line parameter through the main method
I don't know if this will work suit your needs or not, but you could also take a look at File association in Mac
There's many choices on how to make a Java program runnable. Like you mention, the simplest choice is to use the command line. If you want to make it work with most OS's GUI interfaces (and the Open With dialog) the easiest choice is to make an executable jar. IDEs can make this very easy for you, in Eclipse just right-click on the project and select Export > Java > Runnable JAR file.
Another excellent option is to turn your application into a Java Web Start application, which lets users easily run Java programs being served up online.
Alternatively, like you mention, you could convert it into an .exe file:
Compiling a java program into an executable
How do I create an .exe for a Java program?
How can I convert my Java program to an .exe file?
Deploy the app. using Java Web Start.
JWS provides many appealing features including, but not limited to, splash screens, desktop integration, file associations, automatic update (including lazy downloads and programmatic control of updates), partitioning of natives & other resource downloads by platform, architecture or Java version, configuration of run-time environment (minimum J2SE version, run-time options, RAM etc.), easy management of common resources using extensions..
Here is a demo. of the file services in which the app. is associated with the file type .zzz.
..does it get passed via the windows file chooser?
No. It gets passed to the main as either -open filename or -print filename. What the app. does with those strings is up to it. The demo. linked above will prompt the user in the sand-boxed version, simply because it is sand-boxed. The other one should work without showing prompt or dialog.