Applications often need to display dialogs for specific tasks such as opening a file. UI libraries typically provide standard dialogs for these purposes. JGUIraffe offers an abstraction layer through which standard dialogs can be displayed and the data entered in them can be processed.
Concrete standard dialogs are made available via service interfaces located
below the net.sf.jguiraffe.gui.dlg
package. These interfaces
usually define one or more showXXX()
methods through which
different variants of the underlying dialog can be displayed. The methods
expect an object with dialog-specific options; this can be used to
customize the dialog to a certain degree. There is a base class for all
options classes in form of the
AbstractDialogOptions
class. It defines a number of
properties that are common to all standard dialogs. A concrete dialog
service defines its own option class or sometimes even multiple ones.
When the user closes a standard dialog via the OK button a result is
produced that needs to be passed back to the application. A dialog to open
a file for example returns the java.io.File
object that the
user has selected. The propagation of the dialog result is done via a
callback object that is defined in the options for the dialog. There is a
generic result callback interface named
DialogResultCallback
. The base class for all option classes,
AbstractDialogOptions
, expects such a callback object as a
constructor argument; so this information must be provided when an instance
is created. Optionally, an arbitrary context data object can be specified
together with the callback. When the callback is invoked the data object is
passed as well. Here an application can provide context information
relevant for the processing of the dialog result.
If the user cancels the dialog, per default no action is performed. (The
result callback is not invoked because no result object is available.) It
is, however, possible to specify a canceled callback (an object
implementing the
DialogCanceledCallback
interface). This is optional; if such a
callback is present, it is invoked rather than the result callback when the
dialog is canceled. (Again a context data object can be specified to be
passed to the callback.)
Instances of dialog services can be obtained via the dependency injection framework; they are declared in the standard beans definition file shipped with JGUIraffe and thus can be referenced from the application's bean context or from builder scripts. It is for instance possible to inject a service reference into a task or command object that is triggered by a UI element.
In the following sub sections the usage of concrete dialog services is described. The examples provided with these discussions will further clarify the explanations made so far.
Allowing the user to select a file to be opened or saved is a frequent use
case. UI platforms typically support this use case by providing their own
dialog classes. Swing for instance has the JFileChooser
class
that contains a full implementation of a file selection dialog; in JavaFX
there are the FileChooser
and DirectoryChooser
classes that delegate to standard dialogs of the operating system. The
FileChooserDialogService
service interface serves as an
abstraction over these classes. It offers methods to support the following
use cases:
All service methods expect as single argument an options object that allows a customization of the resulting dialog. As the different types of dialogs supported by the service differ in the options that can be adjusted, there are multiple concrete option classes. All of them allow the configuration of standard dialog properties (the mandatory result callback, the optional canceled callback, and the optional dialog title). In addition, they define some properties specific to the dialog type.
The dialog to choose a directory offers the fewest customization options.
It is configured using an object of the
DirectoryChooserOptions
class. It allows setting the initial
directory that is to be displayed when the dialog is shown. The user can
then confirm this directory or navigate to a different one.
The dialogs for selecting files support some more configuration options.
They are defined by the abstract base class
AbstractFileChooserOptions
; from this class the two concrete
option classes
FileChooserOptions
and
MultiFileChooserOptions
are derived. (These classes only differ
in the result type: the former expects a single java.io.File
as result and is used for the dialogs to open a file and to save a file;
the latter is used by the dialog to open multiple files and thus expects a
list of files as result.) The configuration options defined by these
classes include the following properties:
Images (*.jpg; *.gif; *.png)
; by selecting one of these
filters, the user can restrict the files that are displayed in the
dialog.
The example application defines an action that displays a dialog to open a
file. The file is then opened with the application associated with its file
extension. The code can be found in the SelectAndOpenFileTask
class in the demo application. Here we present some fragments from this
class.
The open dialog should contain some filters for frequently used file types.
For this purpose, the class defines a couple of constants of the type
FileExtensionFilter
. Each filter corresponds to a specific file
type and can consist of multiple file extensions:
/** Filter to display all files. */ private static final FileExtensionFilter FILTER_ALL = new FileExtensionFilter( TextResource.fromResourceID("fc_filter_all"), FileExtensionFilter.EXT_ALL_FILES); /** Filter to display image files. */ private static final FileExtensionFilter FILTER_IMAGES = new FileExtensionFilter( TextResource.fromResourceID("fc_filter_images"), "jpg", "jpeg", "gif", "bmp", "png"); /** Filter to display audio files. */ private static final FileExtensionFilter FILTER_AUDIO = new FileExtensionFilter( TextResource.fromResourceID("fc_filter_audio"), "mp3", "ogg", "wav", "au"); /** Filter to display text files. */ private static final FileExtensionFilter FILTER_TEXT = new FileExtensionFilter( TextResource.fromResourceID("fc_filter_text"), "txt", "doc", "pdf"); /** The list of special file extension filters. */ private static final List<FileExtensionFilter> FILTERS = Arrays.asList(FILTER_ALL, FILTER_IMAGES, FILTER_AUDIO, FILTER_TEXT);
Note that there is an explicit entry to list all files - the first one which is selected per default. In order to display the file chooser dialog, a reference to the dialog service must be available. It is passed to the constructor of the task class. We will see later how it is resolved in the builder script:
/** The service for displaying file chooser dialogs. */ private final FileChooserDialogService fileChooserService; /** * Creates a new instance of {@code SelectAndOpenFileTask} and initializes * it with a reference to the file chooser service. * * @param service the file chooser service * @param ctrl the main window controller */ public SelectAndOpenFileTask(FileChooserDialogService service, MainWndController ctrl) { fileChooserService = service; ... }
The service reference is used when the task gets executed, i.e. in its
run()
method. It is passed an options object with some
configuration options. The options also contain the callback to be invoked
with the file selected by the user:
@Override public void run() { DialogResultCallback<File, Void> callback = new DialogResultCallback<File, Void>() { @Override public void onDialogResult(File result, Void data) { openDialogResult(result); } }; FileChooserOptions options = new FileChooserOptions(callback) .setTitleResource("fc_title") .setFilters(FILTERS) .setInitialDirectory(new File(System.getProperty("java.io.tmpdir"))); fileChooserService.showOpenFileDialog(options); } /** * Opens the file that has been selected in the file chooser dialog. * * @param file the result file */ private void openDialogResult(final File file) { ... }
The callback used by this example just delegates to a method that further
processes the resulting File
object; a context data object is
not needed here, therefore, the callback is of type <File, Void>. As
further configuration options a dialog title, a list of filters, and the
initial directory are defined. (The latter is just set to the user's
temporary folder. A more sophisticated implementation would probably store
the directory of the last file that was selected; so the next time the
dialog is opened, the user can continue in this same directory.)
The one piece that is missing is the declaration of the
SelectAndOpenFileTask
instance in the builder script. (It is a
task class that is associated with an action.) The bean definition is shown
in the fragment below. The relevant part is the first parameter passed to
the constructor. Here the file chooser service is referenced under its
well-known name:
<!-- Extras select and open file task --> <di:bean name="selectAndOpenTask" beanClass="net.sf.jguiraffe.examples.tutorial.mainwnd.SelectAndOpenFileTask"> <di:constructor> <di:param refName="jguiraffe.fileChooserService"/> <di:param refName="windowController"/> </di:constructor> </di:bean>