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