/*
* Copyright (c) 2015. , Beaufort 8
* released under MIT License
* http://opensource.org/licenses/MIT
*/
package de.elggconnect.elggconnectclient;
import de.elggconnect.elggconnectclient.controller.MainController;
import de.elggconnect.elggconnectclient.manager.StatusUserManager;
import de.elggconnect.elggconnectclient.model.StatusUserObject;
import de.elggconnect.elggconnectclient.util.*;
import de.elggconnect.elggconnectclient.webservice.AuthGetToken;
import de.elggconnect.elggconnectclient.webservice.StatusUser;
import de.elggconnect.elggconnectclient.webservice.WebService;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.awt.*;
import java.io.IOException;
import java.util.*;
/**
* ElggConnect Main Application Class
* This Class stars the Application and create a TrayIcon.
*
* @author Alexander Stifel
* @author Beaufort 8
*/
public class Main extends Application {
// region Attributes
// BASE URL and BASE_API_URL to a Elgg instance
public static String BASE_URL;
public static String BASE_API_URL;
//PopupMenu for the TrayIcon
private static final PopupMenu popup = new PopupMenu();
//Logger
public static TimerTask timerTask;
private static ResourceBundle messages;
// ImageHandler for loading the right images
private ImageHandler imageHandler = new ImageHandler();
// Application stage is stored so that it can be shown and hidden
private Stage stage;
// a timer allowing the tray icon to provide a periodic notification event.
private Timer notificationTimer = new Timer();
// TrayIcon
private TrayIcon trayIcon;
// UserAuthentication Instance
private UserAuthentication userAuthentication = UserAuthentication
.getInstance();
// StatusUserManager Instance
private StatusUserManager statusUserManager = StatusUserManager
.getInstance();
// Standard menu items for the PopupMenu
private MenuItem miExit;
private MenuItem miPreference;
public static Locale locale;
private Notification.Notifier notifier;
// endregion
/**
* Start Application
*
* @param args
* @throws IOException
* @throws AWTException
*/
public static void main(String[] args) {
//Load Application Properties
PropertyLoader propertyLoader = new PropertyLoader();
BASE_URL = propertyLoader.getBaseUrl();
BASE_API_URL = BASE_URL + "services/api/rest/json/";
//Get System Language
String systemLanguage = System.getProperty("user.language");
//Check if System Language is supported or use en as default
if (!Objects.equals(systemLanguage, "de") && !Objects.equals(systemLanguage, "en")) {
systemLanguage = "en";
}
locale = new Locale.Builder().setLanguage(systemLanguage).build();
//Load Strings
messages = ResourceBundle.getBundle("config.elggconnect", locale);
//launches the JavaFX application.
launch(args);
}
/**
* sets up the javafx application and load tray icons
*
* @param stage
*/
@Override
public void start(final Stage stage) {
// stores a reference to the stage.
this.stage = stage;
// Set Title
this.stage.setTitle(messages.getString("key.preferences"));
// Set Icon the Application Icon
this.stage.getIcons().add(imageHandler.getApplicationIcon());
// Windows is not resizable
this.stage.setResizable(false);
// Load trayIcon for each status
try {
// Load Preferences FXML and set up the tray icon
this.stage.setScene(new Scene(loadApplicationPanes()));
// load and set the css to Scene
this.stage.getScene().getStylesheets().setAll(getClass().getResource("/css/style.css").toExternalForm());
// instructs the javafx system not to exit implicitly when the
// Preferences window is closed.
Platform.setImplicitExit(false);
// sets up the tray icon (using awt code run on the swing thread).
javax.swing.SwingUtilities.invokeLater(this::addAppToTray);
} catch (Exception e) {
System.err.println(e.getMessage());
}
//init notifier
notifier = Notification.Notifier.INSTANCE;
}
/**
* Loads the mainPane fxml layout.
* Sets up the scene switching SceneNavigator.
* Loads the login and logout scene into the scene navigator.
*
* @return the main pane with default view.
* @throws IOException if the pane could not be loaded.
*/
private Pane loadApplicationPanes() throws IOException {
FXMLLoader loader = new FXMLLoader();
//setResource Bundle
loader.setResources(ResourceBundle.getBundle("config.elggconnect", locale));
//Load main fxml layout
Pane mainPane = loader.load(getClass().getResource(SceneNavigator.MAIN).openStream());
MainController mainController = loader.getController();
SceneNavigator.setController(mainController);
//Load Login and Logout Scenes
FXMLLoader loginLoader = new FXMLLoader(getClass().getResource(SceneNavigator.LOGIN));
loginLoader.setResources(ResourceBundle.getBundle("config.elggconnect", locale));
FXMLLoader logoutLoader = new FXMLLoader(getClass().getResource(SceneNavigator.LOGOUT));
logoutLoader.setResources(ResourceBundle.getBundle("config.elggconnect", locale));
//Store the Scenes and Controller into the SceneNavigator
SceneNavigator.setLoginScene(loginLoader.load(), loginLoader.getController());
SceneNavigator.setLogoutScene(logoutLoader.load(), logoutLoader.getController());
//show login view as default
SceneNavigator.loadLoginScene();
return mainPane;
}
/**
* Sets up a system tray icon for the application.
*/
private void addAppToTray() {
try {
// ensure awt toolkit is initialized.
Toolkit.getDefaultToolkit();
// app requires system tray support, just exit if there is no
// support.
if (!SystemTray.isSupported()) {
System.out.println("No system tray support, application exiting.");
Platform.exit();
}
// set up a system tray icon.
SystemTray tray = SystemTray.getSystemTray();
this.trayIcon = new TrayIcon(imageHandler.getTrayiconInactive(),
"ElggConnect");
//Sets the auto-size property to fit the space on the tray
this.trayIcon.setImageAutoSize(true);
// if the user double-clicks on the tray icon, show the preferences stage.
this.trayIcon.addActionListener(event -> Platform
.runLater(this::showPreferences));
//Set up the Standard menu items for the PopupMenu
this.miPreference = new MenuItem(messages.getString("key.preferences"));
this.miPreference.addActionListener(event -> Platform
.runLater(this::showPreferences));
// to really exit the application, the user must go to the system
// tray icon and select the exit option, this will shutdown JavaFX and remove
// the tray icon (removing the tray icon will also shut down AWT).
this.miExit = new MenuItem(messages.getString("key.quit"));
this.miExit.addActionListener(event -> {
this.notificationTimer.cancel();
Platform.exit();
tray.remove(this.trayIcon);
});
// setup the popup menu for the application.
popup.add(this.miPreference);
popup.addSeparator();
popup.add(this.miExit);
this.trayIcon.setPopupMenu(popup);
// create a timer which periodically displays a notification
// message.
timerTask = new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> {
//Check if Username and Password exist
if (userAuthentication.isEmpty()) {
SceneNavigator.loadLoginScene();
//Build Default PopupMenu
popup.removeAll();
popup.addSeparator();
popup.add(miPreference);
popup.addSeparator();
popup.add(miExit);
trayIcon.setPopupMenu(Main.popup);
trayIcon.setImage(imageHandler.getTrayiconInactive());
showPreferences();
} else {
SceneNavigator.loadLogoutScene();
userAuthentication.connect();
checkUserStatusNow();
}
});
}
};
notificationTimer.schedule(
timerTask, 0, // 0 seconds after Application start
180_000 // every 3 minutes
);
// add the application tray icon to the system tray.
tray.add(trayIcon);
} catch (AWTException e) {
System.err.println("Unable to init system tray" + e.getMessage());
}
}
private void checkUserStatusNow() {
WebService webService = new WebService();
//Run StatusUser Web API Method
Long result = webService.executeAPIMethod(new StatusUser(
userAuthentication.getAuthToken()));
if (result == 0) { // OK
updateTrayIcon();
} else if (result == -20) { // Token is not valid get a new one
UserAuthentication userAuthentication = UserAuthentication.getInstance();
webService.executeAPIMethod(new AuthGetToken(userAuthentication.getUsername(), userAuthentication.getPassword()));
updateTrayIcon();
} else if (result == -30) { //Problem
System.out.println("No Internet Connection");
this.trayIcon.setImage(imageHandler.getTrayiconError());
} else {
System.out.println("Problem while executing WebService UserStatus");
this.trayIcon.setImage(imageHandler.getTrayiconError());
}
}
/**
* Shows the application stage and ensures that it is brought ot the front
* of all stages.
*/
private void showPreferences() {
if (stage != null) {
stage.show();
stage.toFront();
}
}
/**
* Updates the TrayIcon if there is new content
*/
private void updateTrayIcon() {
// Check if there are unread Content
if (StatusUserManager.getInstance().unreadStatusUserObjects()) {
this.trayIcon.setImage(imageHandler.getTrayiconNotification());
updateTrayIconMenu();
} else {
updateTrayIconMenu();
this.trayIcon.setImage(imageHandler.getTrayiconActive());
}
}
/**
* Updates the Tray icon Menu depends on the UserStatus Request
*/
private void updateTrayIconMenu() {
java.util.List<MenuItem> statusUserMenuItems = new ArrayList<>();
Main.popup.removeAll(); // Remove all MenuItems
// Add all StatusObjects to a list
for (StatusUserObject statusUserObject : statusUserManager
.getStatusUserObjects()) {
//Check notifications
checkNotification(statusUserObject);
if (statusUserObject.getCount() == 0) {
MenuItem menuItem = new MenuItem(statusUserObject.getName());
menuItem.addActionListener(event -> URLHandler.openURL(BASE_URL
+ statusUserObject.getUrl()));
menuItem.setName(statusUserObject.getType());
statusUserMenuItems.add(menuItem);
} else {
MenuItem menuItem = new MenuItem(statusUserObject.getName() + ": "
+ statusUserObject.getCount());
menuItem.addActionListener(event -> URLHandler.openURL(BASE_URL
+ statusUserObject.getUrl()));
menuItem.setName(statusUserObject.getType());
statusUserMenuItems.add(menuItem);
}
}
//Add a Separator if Item type changed
for (int i = 0; i < statusUserMenuItems.size(); i++) {
Main.popup.add(statusUserMenuItems.get(i));
if (i + 1 < statusUserMenuItems.size()) {
if (!statusUserMenuItems.get(i).getName().equals(statusUserMenuItems.get(i + 1).getName())) {
Main.popup.addSeparator();
}
}
}
//Add Standard MenuItems
Main.popup.addSeparator();
Main.popup.add(miPreference);
Main.popup.addSeparator();
Main.popup.add(this.miExit);
this.trayIcon.setPopupMenu(Main.popup);
}
/**
* Notifies User if there is unread content
* check notification settings
*/
private void checkNotification(StatusUserObject so) {
if (userAuthentication.getNotification()){
if (so.getType().equals("notification") && so.getNewCount() > 0) {
notifier.notify(new Notification(so.getName(), so.getText(), so.getUrl()));
}
}
}
}