1 /*
2 * *************************************************************************************************************************************************************
3 *
4 * SteelBlue: DCI User Interfaces
5 * http://tidalwave.it/projects/steelblue
6 *
7 * Copyright (C) 2015 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8 *
9 * *************************************************************************************************************************************************************
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18 *
19 * *************************************************************************************************************************************************************
20 *
21 * git clone https://bitbucket.org/tidalwave/steelblue-src
22 * git clone https://github.com/tidalwave-it/steelblue-src
23 *
24 * *************************************************************************************************************************************************************
25 */
26 package it.tidalwave.ui.javafx.impl.filechooser;
27
28 import jakarta.annotation.Nonnull;
29 import jakarta.annotation.Nullable;
30 import java.util.concurrent.Executor;
31 import java.util.function.Supplier;
32 import java.io.File;
33 import java.nio.file.Path;
34 import javafx.stage.DirectoryChooser;
35 import javafx.stage.FileChooser;
36 import javafx.stage.Window;
37 import javafx.application.Platform;
38 import it.tidalwave.ui.core.BoundProperty;
39 import it.tidalwave.ui.core.UserNotificationWithFeedback;
40 import it.tidalwave.ui.javafx.impl.common.DelegateSupport;
41 import lombok.extern.slf4j.Slf4j;
42 import static it.tidalwave.ui.javafx.impl.DefaultJavaFXBinder.enforceFxApplicationThread;
43
44 /***************************************************************************************************************************************************************
45 *
46 * @author Fabrizio Giudici
47 *
48 **************************************************************************************************************************************************************/
49 @Slf4j
50 public class FileChooserBindings extends DelegateSupport
51 {
52 /***********************************************************************************************************************************************************
53 *
54 **********************************************************************************************************************************************************/
55 public FileChooserBindings (@Nonnull final Executor executor, @Nonnull final Supplier<Window> mainWindow)
56 {
57 super(executor, mainWindow);
58 }
59
60 /***********************************************************************************************************************************************************
61 * {@inheritDoc}
62 **********************************************************************************************************************************************************/
63 public void openFileChooserFor (@Nonnull final UserNotificationWithFeedback notification,
64 @Nonnull final BoundProperty<Path> selectedFile)
65 {
66 log.debug("openFileChooserFor({}, {})", notification, selectedFile);
67 enforceFxApplicationThread();
68
69 final var fileChooser = new FileChooser();
70 fileChooser.setTitle(notification.getCaption());
71 fileChooser.setInitialDirectory(selectedFile.get().toFile());
72
73 // It seems we need to take care of modality: https://javafx-jira.kenai.com/browse/RT-13949
74 final var file = runWhileDisabling(mainWindow.get(), () -> fileChooser.showOpenDialog(mainWindow.get()));
75
76 notifyFile(file, notification, selectedFile);
77 }
78
79 /***********************************************************************************************************************************************************
80 * {@inheritDoc}
81 **********************************************************************************************************************************************************/
82 public void openDirectoryChooserFor (@Nonnull final UserNotificationWithFeedback notification,
83 @Nonnull final BoundProperty<Path> selectedFolder)
84 {
85 log.debug("openDirectoryChooserFor({}, {})", notification, selectedFolder);
86 enforceFxApplicationThread();
87
88 final var directoryChooser = new DirectoryChooser();
89 directoryChooser.setTitle(notification.getCaption());
90 directoryChooser.setInitialDirectory(selectedFolder.get().toFile());
91
92 // It seems we need to take care of modality: https://javafx-jira.kenai.com/browse/RT-13949
93 final var file = runWhileDisabling(mainWindow.get(), () -> directoryChooser.showDialog(mainWindow.get()));
94
95 notifyFile(file, notification, selectedFolder);
96 }
97
98 /***********************************************************************************************************************************************************
99 *
100 **********************************************************************************************************************************************************/
101 private void notifyFile (@Nullable final File file,
102 @Nonnull final UserNotificationWithFeedback notification,
103 @Nonnull final BoundProperty<Path> selectedFile)
104 {
105 Platform.runLater(() ->
106 {
107 try
108 {
109 if (file == null)
110 {
111 notification.cancel();
112 }
113 else
114 {
115 selectedFile.set(file.toPath());
116 notification.confirm();
117 }
118 }
119 catch (Exception e)
120 {
121 log.warn("", e);
122 }
123 });
124 }
125 }