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  import javafx.application.Application;
24  import javafx.application.Platform;
25  import javafx.collections.FXCollections;
26  import javafx.collections.ObservableList;
27  import javafx.scene.Node;
28  import javafx.scene.Scene;
29  import javafx.scene.control.Label;
30  import javafx.scene.control.Separator;
31  import javafx.scene.control.TextArea;
32  import javafx.scene.image.Image;
33  import javafx.scene.layout.BorderPane;
34  import javafx.scene.layout.VBox;
35  import javafx.stage.Stage;
36  
37  import org.kordamp.ikonli.Ikon;
38  import org.kordamp.ikonli.javafx.FontIcon;
39  
40  import de.spiritscorp.datasync.Main;
41  import de.spiritscorp.datasync.controller.MainViewController;
42  import de.spiritscorp.datasync.controller.SyncJobContext;
43  import de.spiritscorp.datasync.controller.ViewController;
44  import de.spiritscorp.datasync.io.Debug;
45  import de.spiritscorp.datasync.io.PreferenceManager;
46  import de.spiritscorp.datasync.theme.AppTheme;
47  import de.spiritscorp.datasync.theme.DarkSlateTheme;
48  import de.spiritscorp.datasync.theme.MatrixTerminalTheme;
49  import de.spiritscorp.datasync.theme.NordicLightTheme;
50  
51  /**
52   * Main Entry Point Orchestrator managing operational state transactions switcher channels,
53   * initialization parameters, and global view configuration lifecycle processes.
54   *
55   * @author Tom Spirit
56   */
57  public class Gui extends Application {
58  
59  	/** The delay time in seconds used for displaying or fading out status and informational messages within the GUI. */
60  	public static final int INFO_DELAY = 4;
61  	static final String CSS_BUTTON_ICON = "button-icon";
62  	private static final int ICON_SIZE = 20;
63  
64  	private final ObservableList<SyncJobContext> jobList = FXCollections.observableArrayList();
65  	private ViewController controller;
66  
67  	private final ObservableList<AppTheme> availableThemes = FXCollections.observableArrayList(
68  			new DarkSlateTheme(),
69  			new MatrixTerminalTheme(),
70  			new NordicLightTheme() );
71  	private AppTheme currentTheme = availableThemes.getFirst();
72  
73  	private Scene mainScene;
74  	private SidebarView sidebarView;
75  	private WorkspaceView workspaceView;
76  	private SyncJobContext currentActiveJob;
77  	private Stage windowStage;
78  
79  	/**
80  	 * Represents the structural visibility layers and active UI states of the main Viewport container.
81  	 */
82  	public enum ViewState {
83  		/**
84  		 * The main monitoring interface showing active background synchronizations and statistics.
85  		 */
86  		MONITOR,
87  
88  		/**
89  		 * The configuration interface for application-wide rules and job setups.
90  		 */
91  		SETTINGS,
92  
93  		/**
94  		 * The application info, versioning, and about page layer.
95  		 */
96  		INFO
97  	}
98  
99  	private ViewState currentViewState = ViewState.MONITOR;
100 
101 	/**
102 	 * Utility method allocating custom font vector metrics icons definitions graphics layouts.
103 	 *
104 	 * @param ikon Selected base vector item index.
105 	 *
106 	 * @return Prepared graphic FontIcon instance node.
107 	 */
108 	public static FontIcon createIcon( final Ikon ikon ) {
109 		final FontIcon icon = new FontIcon( ikon );
110 		icon.setIconSize( ICON_SIZE );
111 		return icon;
112 	}
113 
114 	@Override
115 	public void start( final Stage primaryStage ) {
116 		this.windowStage = primaryStage;
117 		this.controller = new MainViewController( this );
118 		this.controller.registerNativeShutdownHook();
119 
120 		PreferenceManager prefMan = PreferenceManager.getInstance();
121 		AppTheme theme = prefMan.getTheme();
122 		if( theme instanceof DarkSlateTheme ) {
123 			this.currentTheme = availableThemes.get( 0 );
124 		}else if( theme instanceof MatrixTerminalTheme ) {
125 			this.currentTheme = availableThemes.get( 1 );
126 		}else if( theme instanceof NordicLightTheme ) {
127 			this.currentTheme = availableThemes.get( 2 );
128 		}
129 		prefMan.setTheme( currentTheme );
130 
131 		primaryStage.setTitle( "DataSync Advanced Management Platform" );
132 		primaryStage.getIcons().add( new Image( getClass().getResourceAsStream( "/icons/16x16.png" ) ) );
133 		Platform.setImplicitExit( false );
134 		primaryStage.setOnCloseRequest( _ -> {
135 			Debug.printDebug( "[Info] Window hidden. Application processing stays active in background." );
136 			controller.runInBackground( false );
137 		} );
138 		sidebarView = new SidebarView( this, controller );
139 		workspaceView = new WorkspaceView( this, controller );
140 
141 		final BorderPane mainLayout = new BorderPane();
142 		mainLayout.setLeft( sidebarView );
143 		mainLayout.setCenter( workspaceView );
144 
145 		mainScene = new Scene( mainLayout, 1350, 800 );
146 		if( !getJobList().isEmpty() ) {
147 			sidebarView.getSidebarListView().getSelectionModel().select( 0 );
148 		}
149 		currentTheme.apply( mainScene );
150 
151 		primaryStage.setScene( mainScene );
152 		if( Main.isFirstStart() ) {
153 			controller.runInBackground( Main.isFirstStart() );
154 		}else {
155 			primaryStage.show();
156 		}
157 	}
158 
159 	/**
160 	 * Updates global active tracking routes navigation indexes updating workspace render cycles.
161 	 *
162 	 * @param state Target destination navigation path selection layer.
163 	 */
164 	public void setViewState( final ViewState state ) {
165 		this.currentViewState = state;
166 		if( state == ViewState.INFO ) {
167 			workspaceView.refreshView( state, null );
168 			workspaceView.displayCustomViewNode( buildAboutInfoNode() );
169 		}else {
170 			workspaceView.refreshView( currentViewState, currentActiveJob );
171 		}
172 	}
173 
174 	/**
175 	 * Updates central contextual execution active jobs binding structures hooks.
176 	 *
177 	 * @param job Active core source entity context.
178 	 */
179 	public void setCurrentActiveJob( final SyncJobContext job ) {
180 		this.currentActiveJob = job;
181 		workspaceView.bindJob( job );
182 		if( this.currentViewState == ViewState.INFO ) {
183 			workspaceView.displayCustomViewNode( buildAboutInfoNode() );
184 		}else {
185 			workspaceView.refreshView( currentViewState, job );
186 		}
187 	}
188 
189 	/**
190 	 * Changes the runtime theme context and triggers immediate scene redraw.
191 	 *
192 	 * @param newTheme The target AppTheme strategy implementation.
193 	 */
194 	public void changeTheme( final AppTheme newTheme ) {
195 		if( newTheme != null && mainScene != null ) {
196 			this.currentTheme = newTheme;
197 			// Clear previous runtime stylesheets to avoid collision matrix
198 			mainScene.getStylesheets().clear();
199 			this.currentTheme.apply( mainScene );
200 		}
201 	}
202 
203 	/**
204 	 * Proxy method to delegate temporary status messages to the active workspace view boundary.
205 	 *
206 	 * @param message      The localized text string to display.
207 	 * @param notifyStatus The theme-defined CSS class for contextual coloring.
208 	 * @param durationSec  The visibility lifespan of the message in seconds.
209 	 */
210 	public void showStatusNotification( final String message, final NotifyStatus notifyStatus, final int durationSec ) {
211 		if( workspaceView != null ) {
212 			workspaceView.displayTemporaryStatus( message, notifyStatus, durationSec );
213 		}
214 	}
215 
216 	/**
217 	 * Initializes saved job configurations within the runtime context.
218 	 * This resets the current tracking list and populates it with the provided synchronization jobs.
219 	 *
220 	 * @param jobList the observable list of {@link SyncJobContext} instances to set
221 	 */
222 	public void setInitialJobConfigurations( final ObservableList<SyncJobContext> jobList ) {
223 		this.jobList.clear();
224 		this.jobList.addAll( jobList );
225 	}
226 
227 	/**
228 	 * Returns the observable list of currently tracked synchronization jobs.
229 	 *
230 	 * @return the observable list of {@link SyncJobContext} instances
231 	 */
232 	public ObservableList<SyncJobContext> getJobList() { return jobList; }
233 
234 	/**
235 	 * Retrieves the primary JavaFX Stage window context associated with this manager.
236 	 *
237 	 * @return the current {@link Stage} instance
238 	 */
239 	public Stage getWindowStage() { return windowStage; }
240 
241 	/**
242 	 * Returns the list of all application themes available for selection.
243 	 *
244 	 * @return an observable list of {@link AppTheme} options
245 	 */
246 	public ObservableList<AppTheme> getAvailableThemes() { return availableThemes; }
247 
248 	/**
249 	 * Retrieves the currently active application theme configuration.
250 	 *
251 	 * @return the currently applied {@link AppTheme}
252 	 */
253 	public AppTheme getCurrentTheme() { return currentTheme; }
254 
255 	public boolean isShowing() { return windowStage.isShowing(); }
256 
257 	/**
258 	 * Builds standard software information metrics description panels nodes.
259 	 */
260 	private Node buildAboutInfoNode() {
261 		final VBox infoBox = new VBox( 10 );
262 		infoBox.getStyleClass().addAll( "info-box" );
263 		final Label appTitle = new Label( "DataSync Core Engine" );
264 		appTitle.getStyleClass().addAll( "app-title-label" );
265 		final Label version = new Label( "Programmversion: " + Main.VERSION );
266 		final Label vendor = new Label( "Lizenznehmer / Entwickler: Tom Spirit" );
267 		final Label copyright = new Label( "Copyright: Licensed under GNU GPL v3.0 Copyleft System." );
268 		final Separator sep = new Separator();
269 		final TextArea legalText = new TextArea(
270 				"""
271 						This program is free software; you can redistribute it and/or modify
272 						it under the terms of the GNU General Public License as published by
273 						the Free Software Foundation; either version 3 of the License.
274 
275 						This program is distributed in the hope that it will be useful, without any warranty.
276 						""" );
277 		legalText.setEditable( false );
278 		legalText.setPrefHeight( 150 );
279 		legalText.getStyleClass().addAll( "legalText" );
280 
281 		infoBox.getChildren().addAll( appTitle, version, vendor, copyright, sep, legalText );
282 		return infoBox;
283 	}
284 }