View Javadoc
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 }