Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.stage;
027
028import java.io.File;
029import java.util.Arrays;
030import java.util.Collections;
031import java.util.List;
032
033import javafx.beans.property.ObjectProperty;
034import javafx.beans.property.SimpleObjectProperty;
035import javafx.beans.property.SimpleStringProperty;
036import javafx.beans.property.StringProperty;
037import javafx.collections.FXCollections;
038import javafx.collections.ObservableList;
039
040import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
041import com.sun.javafx.tk.FileChooserType;
042import com.sun.javafx.tk.Toolkit;
043
044/**
045 * Provides support for standard platform file dialogs. These dialogs have look
046 * and feel of the platform UI components which is independent of JavaFX.
047 * <p>
048 * On some platforms where file access may be restricted or not part of the user
049 * model (for example, on some mobile or embedded devices), opening a file
050 * dialog may always result in a no-op (that is, null file(s) being returned).
051 * </p>
052 * <p>
053 * A {@code FileChooser} can be used to invoke file open dialogs for selecting
054 * single file ({@code showOpenDialog}), file open dialogs for selecting
055 * multiple files ({@code showOpenMultipleDialog}) and file save dialogs
056 * ({@code showSaveDialog}). The configuration of the displayed dialog is
057 * controlled by the values of the {@code FileChooser} properties set before the
058 * corresponding {@code show*Dialog} method is called. This configuration
059 * includes the dialog's title, the initial directory displayed in the dialog
060 * and the extension filter(s) for the listed files. For configuration
061 * properties which values haven't been set explicitly, the displayed dialog
062 * uses their platform default values. A call to a show dialog method is
063 * blocked until the user makes a choice or cancels the dialog. The return
064 * value specifies the selected file(s) or equals to {@code null} if the dialog
065 * has been canceled.
066 * </p>
067 * <p>
068 * Example:
069 * <pre><code>
070 * FileChooser fileChooser = new FileChooser();
071 * fileChooser.setTitle("Open Resource File");
072 * fileChooser.getExtensionFilters().addAll(
073 *         new ExtensionFilter("Text Files", "*.txt"),
074 *         new ExtensionFilter("Image Files", "*.png", "*.jpg", "*.gif"),
075 *         new ExtensionFilter("Audio Files", "*.wav", "*.mp3", "*.aac"),
076 *         new ExtensionFilter("All Files", "*.*"));
077 * File selectedFile = fileChooser.showOpenDialog(mainStage);
078 * if (selectedFile != null) {
079 *    mainStage.display(selectedFile);
080 * }
081 * </code></pre>
082 * </p>
083 */
084public final class FileChooser {
085    /**
086     * Defines an extension filter, used for filtering which files can be chosen
087     * in a FileDialog based on the file name extensions.
088     */
089    public static final class ExtensionFilter {
090        private final String description;
091        private final List<String> extensions;
092
093        /**
094         * Creates an {@code ExtensionFilter} with the specified description
095         * and the file name extensions.
096         * <p>
097         * File name extension should be specified in the {@code *.<extension>}
098         * format.
099         *
100         * @param description the textual description for the filter
101         * @param extensions the accepted file name extensions
102         * @throws NullPointerException if the description or the extensions
103         *      are {@code null}
104         * @throws IllegalArgumentException if the description or the extensions
105         *      are empty
106         */
107        public ExtensionFilter(final String description,
108                               final String... extensions) {
109            validateArgs(description, extensions);
110
111            this.description = description;
112            this.extensions = Collections.unmodifiableList(
113                                      Arrays.asList(extensions.clone()));
114        }
115
116        /**
117         * Creates an {@code ExtensionFilter} with the specified description
118         * and the file name extensions.
119         * <p>
120         * File name extension should be specified in the {@code *.<extension>}
121         * format.
122         *
123         * @param description the textual description for the filter
124         * @param extensions the accepted file name extensions
125         * @throws NullPointerException if the description or the extensions
126         *      are {@code null}
127         * @throws IllegalArgumentException if the description or the extensions
128         *      are empty
129         */
130        public ExtensionFilter(final String description,
131                               final List<String> extensions) {
132            final String[] extensionsArray =
133                    (extensions != null) ? extensions.toArray(
134                                               new String[extensions.size()])
135                                         : null;
136            validateArgs(description, extensionsArray);
137
138            this.description = description;
139            this.extensions = Collections.unmodifiableList(
140                                      Arrays.asList(extensionsArray));
141        }
142
143        /**
144         * Gets the description for this {@code ExtensionFilter}.
145         *
146         * @return the description
147         */
148        public String getDescription() {
149            return description;
150        }
151
152        /**
153         * Gets the file name extensions for this {@code ExtensionFilter}.
154         * <p>
155         * The returned list is unmodifiable and will throw
156         * {@code UnsupportedOperationException} on each modification attempt.
157         *
158         * @return the file name extensions
159         */
160        @ReturnsUnmodifiableCollection
161        public List<String> getExtensions() {
162            return extensions;
163        }
164
165        private static void validateArgs(final String description,
166                                         final String[] extensions) {
167            if (description == null) {
168                throw new NullPointerException("Description must not be null");
169            }
170
171            if (description.isEmpty()) {
172                throw new IllegalArgumentException(
173                        "Description must not be empty");
174            }
175
176            if (extensions == null) {
177                throw new NullPointerException("Extensions must not be null");
178            }
179
180            if (extensions.length == 0) {
181                throw new IllegalArgumentException(
182                        "At least one extension must be defined");
183            }
184
185            for (String extension : extensions) {
186                if (extension == null) {
187                    throw new NullPointerException(
188                            "Extension must not be null");
189                }
190                
191                if (extension.isEmpty()) {
192                    throw new IllegalArgumentException(
193                            "Extension must not be empty");
194                }
195            }
196        }
197    }
198
199    /**
200     * The title of the displayed file dialog.
201     */
202    private StringProperty title;
203
204    public final void setTitle(final String value) {
205        titleProperty().set(value);
206    }
207
208    public final String getTitle() {
209        return (title != null) ? title.get() : null;
210    }
211
212    public final StringProperty titleProperty() {
213        if (title == null) {
214            title = new SimpleStringProperty(this, "title");
215        }
216
217        return title;
218    }
219
220    /**
221     * The initial directory for the displayed file dialog.
222     */
223    private ObjectProperty<File> initialDirectory;
224
225    public final void setInitialDirectory(final File value) {
226        initialDirectoryProperty().set(value);
227    }
228
229    public final File getInitialDirectory() {
230        return (initialDirectory != null) ? initialDirectory.get() : null;
231    }
232
233    public final ObjectProperty<File> initialDirectoryProperty() {
234        if (initialDirectory == null) {
235            initialDirectory = 
236                    new SimpleObjectProperty<File>(this, "initialDirectory");
237        }
238
239        return initialDirectory;
240    }
241
242    /**
243     * The initial file name for the displayed dialog.
244     * <p>
245     * This property is used mostly in the displayed file save dialogs as the
246     * initial file name for the file being saved. If set for a file open
247     * dialog it will have any impact on the displayed dialog only if the
248     * corresponding platform provides support for such property in its
249     * file open dialogs.
250     * </p>
251     *
252     * @since JavaFX 8.0
253     */
254    private ObjectProperty<String> initialFileName;
255
256    public final void setInitialFileName(final String value) {
257        initialFileNameProperty().set(value);
258    }
259
260    public final String getInitialFileName() {
261        return (initialFileName != null) ? initialFileName.get() : null;
262    }
263
264    public final ObjectProperty<String> initialFileNameProperty() {
265        if (initialFileName == null) {
266            initialFileName =
267                    new SimpleObjectProperty<String>(this, "initialFileName");
268        }
269
270        return initialFileName;
271    }
272
273    /**
274     * Specifies the extension filters used in the displayed file dialog.
275     */
276    private ObservableList<ExtensionFilter> extensionFilters =
277            FXCollections.<ExtensionFilter>observableArrayList();
278
279    /**
280     * Gets the extension filters used in the displayed file dialog. Only
281     * one extension filter from the list is active at any time in the displayed
282     * dialog and only files which correspond to this extension filter are
283     * shown. The first extension filter from the list is activated when the
284     * dialog is invoked. Then the user can switch the active extension filter
285     * to any other extension filter from the list and in this way control the
286     * set of displayed files.
287     *
288     * @return An observable list of the extension filters used in this dialog
289     */
290    public ObservableList<ExtensionFilter> getExtensionFilters() {
291        return extensionFilters;
292    }
293
294    /**
295     * Shows a new file open dialog. The method doesn't return until the
296     * displayed open dialog is dismissed. The return value specifies
297     * the file chosen by the user or {@code null} if no selection has been
298     * made. If the owner window for the file dialog is set, input to all
299     * windows in the dialog's owner chain is blocked while the file dialog
300     * is being shown.
301     *
302     * @param ownerWindow the owner window of the displayed file dialog
303     * @return the selected file or {@code null} if no file has been selected
304     */
305    public File showOpenDialog(final Window ownerWindow) {
306        final List<File> selectedFiles =
307                showDialog(ownerWindow, FileChooserType.OPEN);
308
309        return ((selectedFiles != null) && (selectedFiles.size() > 0))
310                ? selectedFiles.get(0) : null;
311    }
312
313    /**
314     * Shows a new file open dialog in which multiple files can be selected.
315     * The method doesn't return until the displayed open dialog is dismissed.
316     * The return value specifies the files chosen by the user or {@code null}
317     * if no selection has been made. If the owner window for the file dialog is
318     * set, input to all windows in the dialog's owner chain is blocked while
319     * the file dialog is being shown.
320     * <p>
321     * The returned list is unmodifiable and will throw
322     * {@code UnsupportedOperationException} on each modification attempt.
323     *
324     * @param ownerWindow the owner window of the displayed file dialog
325     * @return the selected files or {@code null} if no file has been selected
326     */
327    @ReturnsUnmodifiableCollection
328    public List<File> showOpenMultipleDialog(final Window ownerWindow) {
329        final List<File> selectedFiles =
330                showDialog(ownerWindow, FileChooserType.OPEN_MULTIPLE);
331
332        return ((selectedFiles != null) && (selectedFiles.size() > 0))
333                ? Collections.unmodifiableList(selectedFiles)
334                : null;
335    }
336
337    /**
338     * Shows a new file save dialog. The method doesn't return until the
339     * displayed file save dialog is dismissed. The return value specifies the
340     * file chosen by the user or {@code null} if no selection has been made.
341     * If the owner window for the file dialog is set, input to all windows in
342     * the dialog's owner chain is blocked while the file dialog is being shown.
343     *
344     * @param ownerWindow the owner window of the displayed file dialog
345     * @return the selected file or {@code null} if no file has been selected
346     */
347    public File showSaveDialog(final Window ownerWindow) {
348        final List<File> selectedFiles =
349                showDialog(ownerWindow, FileChooserType.SAVE);
350
351        return ((selectedFiles != null) && (selectedFiles.size() > 0))
352                ? selectedFiles.get(0) : null;
353    }
354
355    private List<File> showDialog(final Window ownerWindow,
356                                  final FileChooserType fileChooserType) {
357        return Toolkit.getToolkit().showFileChooser(
358                (ownerWindow != null) ? ownerWindow.impl_getPeer() : null,
359                getTitle(),
360                getInitialDirectory(),
361                getInitialFileName(),
362                fileChooserType,
363                extensionFilters);
364        
365    }
366}