Skip to content

Package: DialogBindings$UrlOpener

DialogBindings$UrlOpener

nameinstructionbranchcomplexitylinemethod
changed(ObservableValue, String, String)
M: 15 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
lambda$changed$0(String)
M: 17 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%

Coverage

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.dialog;
27:
28: import jakarta.annotation.Nonnull;
29: import java.util.Optional;
30: import java.util.concurrent.Executor;
31: import java.util.function.Supplier;
32: import java.io.IOException;
33: import java.net.URI;
34: import java.net.URISyntaxException;
35: import java.awt.Desktop;
36: import javafx.beans.value.ChangeListener;
37: import javafx.beans.value.ObservableValue;
38: import javafx.scene.Node;
39: import javafx.scene.control.Alert;
40: import javafx.scene.control.ButtonType;
41: import javafx.scene.control.Dialog;
42: import javafx.scene.control.Label;
43: import javafx.scene.paint.Color;
44: import javafx.scene.web.WebView;
45: import javafx.stage.Window;
46: import javafx.application.Platform;
47: import it.tidalwave.ui.core.UserNotificationWithFeedback;
48: import it.tidalwave.ui.javafx.impl.common.DelegateSupport;
49: import it.tidalwave.util.BundleUtilities;
50: import it.tidalwave.util.Callback;
51: import lombok.RequiredArgsConstructor;
52: import lombok.SneakyThrows;
53: import lombok.extern.slf4j.Slf4j;
54:
55: /***************************************************************************************************************************************************************
56: *
57: * @author Fabrizio Giudici
58: *
59: **************************************************************************************************************************************************************/
60: @Slf4j
61: public class DialogBindings extends DelegateSupport
62: {
63: @RequiredArgsConstructor
64: private static class UrlOpener implements ChangeListener<String>
65: {
66: @Nonnull
67: private final WebView webView;
68:
69: @Nonnull
70: private final String text;
71:
72: @Override
73: public void changed (final ObservableValue<? extends String> observableValue, final String oldValue, final String newValue)
74: {
75:• if (newValue != null && !newValue.isEmpty())
76: {
77: Platform.runLater(() ->
78: {
79: try
80: {
81: log.debug("Opening {} ...", newValue);
82: Desktop.getDesktop().browse(new URI(newValue));
83: }
84: catch (IOException | URISyntaxException e)
85: {
86: log.warn("", e);
87: }
88: });
89:
90: webView.getEngine().loadContent(text);
91: }
92: }
93: }
94:
95: /***********************************************************************************************************************************************************
96: *
97: **********************************************************************************************************************************************************/
98: public DialogBindings (@Nonnull final Executor executor, @Nonnull final Supplier<Window> mainWindow)
99: {
100: super(executor, mainWindow);
101: }
102:
103: /***********************************************************************************************************************************************************
104: * {@inheritDoc}
105: **********************************************************************************************************************************************************/
106: public void showInModalDialog (@Nonnull final UserNotificationWithFeedback notification,
107: @Nonnull final Optional<Node> node)
108: {
109: // FIXME: should not be needed
110: Platform.runLater(() ->
111: {
112: log.debug("modalDialog({}, {})", node, notification);
113:
114: // final Dialog<ButtonType> dialog = new Dialog<>();
115: final Dialog<ButtonType> dialog = new Alert(Alert.AlertType.NONE);
116: dialog.initOwner(mainWindow.get());
117: dialog.setTitle(notification.getCaption());
118: dialog.setResizable(false);
119: final var dialogPane = dialog.getDialogPane();
120: final var text = notification.getText();
121:
122: if (!text.startsWith("<html>"))
123: {
124: dialog.setContentText(text);
125: node.ifPresent(dialogPane::setContent);
126: }
127: else
128: {
129: final var webView = new WebView();
130: webView.setPrefSize(600, 300); // FIXME: proportional to screen
131: webView.setContextMenuEnabled(false);
132: final var label = new Label();
133: dialogPane.setContent(label);
134: final var fontFamily = label.getFont().getFamily();
135: // System.err.println("FILL " + label.getTextFill());
136: final var textColor = "white"; // FIXME
137: var backgroundColor = "#252525"; // FIXME
138:
139: try
140: {
141: // Available in JDK 18+
142: final var setPageFill = webView.getClass().getDeclaredMethod("setPageFill", Color.class);
143: setPageFill.invoke(webView, Color.TRANSPARENT);
144: backgroundColor = "transparent";
145: }
146: catch (Exception e)
147: {
148: log.trace("WebView.setPageFill() not available", e);
149: }
150:
151: // FIXME
152: final var text2 = BundleUtilities.getMessage(getClass(),"htmlTemplate", text, textColor, backgroundColor, fontFamily);
153: // System.err.println(text2);
154: webView.getEngine().loadContent(text2);
155: webView.getEngine().locationProperty().addListener(new UrlOpener(webView, text2));
156: dialogPane.setContent(webView);
157: }
158:
159: final var feedback = notification.getFeedback();
160: final var hasOnCancel = feedback.canCancel();
161:
162: final var buttonTypes = dialogPane.getButtonTypes();
163: buttonTypes.clear();
164: buttonTypes.add(ButtonType.OK);
165:
166: if (hasOnCancel)
167: {
168: buttonTypes.add(ButtonType.CANCEL);
169: }
170:
171: // okButton.disableProperty().bind(new PropertyAdapter<>(valid)); // FIXME: doesn't work
172:
173: final var result = dialog.showAndWait();
174:
175: if (result.isEmpty())
176: {
177: if (hasOnCancel)
178: {
179: wrap(notification::cancel);
180: }
181: else
182: {
183: wrap(notification::confirm);
184: }
185: }
186: else
187: {
188: if (result.get() == ButtonType.OK)
189: {
190: wrap(notification::confirm);
191: }
192: else if (result.get() == ButtonType.CANCEL)
193: {
194: wrap(notification::cancel);
195: }
196: else
197: {
198: throw new IllegalStateException("Unexpected button pressed: " + result.get());
199: }
200: }
201: });
202: }
203:
204: /***********************************************************************************************************************************************************
205: *
206: **********************************************************************************************************************************************************/
207: @SneakyThrows(Throwable.class)
208: private static void wrap (@Nonnull final Callback callback)
209: {
210: callback.call();
211: }
212: }