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 java.awt.Font;
24  import java.awt.MenuItem;
25  import java.awt.PopupMenu;
26  import java.awt.SystemTray;
27  import java.awt.TrayIcon;
28  import java.awt.image.BufferedImage;
29  import java.io.IOException;
30  import java.util.Objects;
31  
32  import javax.imageio.ImageIO;
33  
34  import de.spiritscorp.datasync.Main;
35  import de.spiritscorp.datasync.controller.BgController;
36  import de.spiritscorp.datasync.io.Debug;
37  import javafx.application.Platform;
38  
39  /**
40   * Encapsulated system tray presenter.
41   * Bridges native AWT desktop toolkit hooks securely onto JavaFX platform thread loops.
42   *
43   * @author Tom Spirit
44   */
45  public class BgView {
46  
47  	private TrayIcon trayIcon;
48  	private final BgController controller;
49  
50  	/**
51  	 * Create the SystemTrayIcon
52  	 *
53  	 * @param controller The controller
54  	 */
55  	public BgView( BgController controller ) {
56  		this.controller = controller;
57  		if( SystemTray.isSupported() ) {
58  			initTray();
59  		}else {
60  			Debug.printDebug( "[DataSync Core] SystemTray wird von diesem Betriebssystem nicht unterstützt." );
61  		}
62  	}
63  
64  	private void initTray() {
65  		final PopupMenu popup = new PopupMenu();
66  		final Font font = new Font( "Comic Sans MS", Font.PLAIN, 14 );
67  
68  		final MenuItem openItem = new MenuItem( "öffnen" );
69  		openItem.setFont( font );
70  		// CRITICAL: Bridge AWT event into the JavaFX Application Thread context safely
71  		openItem.addActionListener( e -> Platform.runLater( () -> {
72  			controller.interruptBgJob( Main.BACKGROUND_THREAD_TIMEOUT );
73  		} ) );
74  
75  		final MenuItem closeItem = new MenuItem( "schließen" );
76  		closeItem.setFont( font );
77  		closeItem.addActionListener( e -> Platform.runLater( controller::requestApplicationShutdown ) );
78  
79  		popup.add( openItem );
80  		popup.addSeparator();
81  		popup.add( closeItem );
82  
83  		// Robustes Laden des Icons über den Context-ClassLoader
84  		BufferedImage trayImage;
85  		try {
86  			trayImage = ImageIO.read( getClass().getResourceAsStream( "/icons/16x16.png" ) );
87  		}catch( final IOException e ) {
88  			Debug.printError( "[DataSync] Tray-Icon nicht gefunden, erstelle Fallback-Pixel." );
89  			trayImage = new BufferedImage( 16, 16, BufferedImage.TYPE_INT_ARGB );
90  		}
91  
92  		this.trayIcon = new TrayIcon( trayImage, "DataSync Platform Console", popup );
93  		this.trayIcon.setImageAutoSize( true );
94  
95  		// Doppel-Klick auf das Icon öffnet die App direkt
96  		this.trayIcon.addActionListener( e -> Platform.runLater( () -> controller.interruptBgJob( Main.BACKGROUND_THREAD_TIMEOUT ) ) );
97  	}
98  
99  	/**
100 	 * @return TrayIcon
101 	 */
102 	public TrayIcon getTrayIcon() { return trayIcon; }
103 
104 	@Override
105 	public int hashCode() {
106 		return Objects.hash( controller, trayIcon );
107 	}
108 
109 	@Override
110 	public boolean equals( final Object obj ) {
111 		if( this == obj ) { return true; }
112 		if( obj == null ) { return false; }
113 		if( getClass() != obj.getClass() ) { return false; }
114 		final BgView other = (BgView) obj;
115 		return Objects.equals( controller, other.controller ) && Objects.equals( trayIcon, other.trayIcon );
116 	}
117 }