1 package de.spiritscorp.datasync.gui;
2
3 /*-
4 * Data Sync
5 *
6 * Copyright © 2022 The Spirit
7 * @email thespirit@spiritscorp.network
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22 /*
23 Data Sync
24
25 @author Tom Spirit
26 @email tomspirit@spiritscorp.network
27
28 Copyright ©
29
30 This program is free software; you can redistribute it and/or modify
31 it under the terms of the GNU General Public License as published by
32 the Free Software Foundation; either version 3 of the License, or
33 (at your option) any later version.
34
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details.
39
40 You should have received a copy of the GNU General Public License
41 along with this program. If not, see <http://www.gnu.org/licenses/>.
42 */
43
44 import java.util.concurrent.CompletableFuture;
45 import java.util.concurrent.ExecutionException;
46
47 import de.spiritscorp.datasync.io.Debug;
48 import javafx.application.Platform;
49 import javafx.scene.control.Alert;
50 import javafx.scene.control.ButtonType;
51 import javafx.stage.Stage;
52
53 /**
54 * Service responsible for managing UI dialogs and alerts.
55 * Ensures strict thread safety by bridging background thread calls to the JavaFX Application Thread.
56 */
57 public class DialogService {
58
59 /** The primary application stage acting as the owner window for modal dialogs. */
60 private final Stage stage;
61
62 /**
63 * Constructs a new DialogService bound to a specific primary window stage.
64 *
65 * @param stage The parent stage container, must not be null
66 * @throws NullPointerException if the provided stage is null
67 */
68 public DialogService( final Stage stage ) {
69 this.stage = stage;
70 }
71
72 /**
73 * Displays a confirmation dialog to the user and blocks until a selection is made.
74 * Automatically handles cross-thread invocations without throwing structural exceptions.
75 *
76 * @param title The descriptive title of the dialog window
77 * @param header The contextual header text of the notification
78 * @param content The message body containing instructions or questions
79 * @return true if the user confirmed via OK, false if canceled or closed
80 */
81 public boolean askUser( final String title, final String header, final String content ) {
82 // Execute immediately if invoked directly on the JavaFX Application Thread
83 if( Platform.isFxApplicationThread() ) { return showConfirmationDialog( title, header, content ); }
84
85 // Bridge execution synchronously if called from a background worker thread
86 final CompletableFuture<Boolean> userResponse = new CompletableFuture<>();
87
88 Platform.runLater( () -> {
89 try {
90 final boolean response = showConfirmationDialog( title, header, content );
91 userResponse.complete( response );
92 }catch( final Exception e ) {
93 userResponse.completeExceptionally( e );
94 }
95 } );
96
97 try {
98 return userResponse.get(); // Halts the background worker here until the user interacts with the UI
99 }catch( final InterruptedException e ) {
100 Thread.currentThread().interrupt();
101 return false;
102 }catch( final ExecutionException e ) {
103 Debug.printDebug( "[Dialog Service Error] Execution Exception -> ", e.getMessage() );
104 Debug.printException( getClass(), e );
105 return false;
106 }
107 }
108
109 /**
110 * Builds and visualizes the native JavaFX Alert window component.
111 * This operation must strictly execute inside the boundaries of the FX core thread.
112 *
113 * @param title The descriptive title of the dialog window
114 * @param header The contextual header text of the notification
115 * @param content The message body containing instructions or questions
116 * @return true if OK was selected, false otherwise
117 */
118 private boolean showConfirmationDialog( final String title, final String header, final String content ) {
119 final Alert confirmation = new Alert( Alert.AlertType.CONFIRMATION, content, ButtonType.OK, ButtonType.CANCEL );
120 confirmation.setTitle( title );
121 confirmation.setHeaderText( header );
122 confirmation.initOwner( stage );
123 return confirmation.showAndWait().orElse( ButtonType.CANCEL ) == ButtonType.OK;
124 }
125 }