/** * */ package application.windows; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.InlineCssTextArea; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import application.Main; import application.tools.ActionTool; import application.tools.InfoTool; import application.tools.NotificationType; import javafx.animation.PauseTransition; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.input.KeyCode; import javafx.scene.layout.GridPane; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.util.Duration; /** * @author GOXR3PLUS * */ public class UpdateWindow extends StackPane { //-------------------------------------------------------------- @FXML private GridPane centerGridPane; @FXML private Label updatesInformationLabel; @FXML private Label comingSoonLabel; @FXML private Label topLabel; @FXML private Button download; @FXML private Button automaticUpdate; @FXML private Button closeWindow; // ------------------------------------------------------------- /** The logger. */ private final Logger logger = Logger.getLogger(getClass().getName()); /** Window **/ private Stage window = new Stage(); private final InlineCssTextArea textArea1 = new InlineCssTextArea(); private final InlineCssTextArea textArea2 = new InlineCssTextArea(); private final VirtualizedScrollPane<InlineCssTextArea> vsPane1 = new VirtualizedScrollPane<>(textArea1); private final VirtualizedScrollPane<InlineCssTextArea> vsPane2 = new VirtualizedScrollPane<>(textArea2); /** * The Thread which is responsible for the update check */ private static Thread updaterThread; /** * Constructor. */ public UpdateWindow() { // ------------------------------------FXMLLOADER ---------------------------------------- FXMLLoader loader = new FXMLLoader(getClass().getResource(InfoTool.FXMLS + "UpdateWindow.fxml")); loader.setController(this); loader.setRoot(this); try { loader.load(); } catch (IOException ex) { logger.log(Level.SEVERE, "", ex); } window.setTitle("Update Window"); window.initStyle(StageStyle.UTILITY); window.setResizable(false); window.setScene(new Scene(this)); window.getScene().setOnKeyReleased(k -> { if (k.getCode() == KeyCode.ESCAPE) window.close(); }); } /** * Called as soon as .fxml is initialized */ @FXML private void initialize() { // -- textArea1.setEditable(false); textArea1.setFocusTraversable(false); //-- vsPane1.setMinSize(500, 425); vsPane1.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); //-- textArea2.setEditable(false); textArea2.setFocusTraversable(false); textArea2.setWrapText(true); //-- vsPane2.setMinSize(500, 425); vsPane2.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); centerGridPane.addRow(1, vsPane1, vsPane2); // -- automaticUpdate automaticUpdate.setOnAction(a -> startXR3PlayerUpdater()); // -- download download.setOnAction(a -> ActionTool.openWebSite("https://sourceforge.net/projects/xr3player/")); // -- closeWindow closeWindow.setOnAction(a -> window.close()); } /** * This method is fetching data from github to check if the is a new update * for XR3Player * * @param showTheWindow * If not update is available then don't show the window */ public synchronized void searchForUpdates(boolean showTheWindow) { // Not already running if (updaterThread != null && updaterThread.isAlive()) return; updaterThread = new Thread(() -> { if (showTheWindow) Platform.runLater( () -> ActionTool.showNotification("Searching for Updates", "Fetching informations from server...", Duration.millis(1000), NotificationType.INFORMATION)); //Check if we have internet connection if (InfoTool.isReachableByPing("www.google.com")) searchForUpdatesPart2(showTheWindow); else Platform.runLater(() -> ActionTool.showNotification("Can't Connect", "Can't connect to the update site :\n1) Maybe there is not internet connection\n2)GitHub is down for maintenance", Duration.millis(2500), NotificationType.ERROR)); }, "Application Update Thread"); updaterThread.setDaemon(true); updaterThread.start(); } private void searchForUpdatesPart2(boolean showTheWindow) { try { Document doc = Jsoup.connect("https://raw.githubusercontent.com/goxr3plus/XR3Player/master/XR3PlayerUpdatePage.html").get(); //Document doc = Jsoup.parse(new File("XR3PlayerUpdatePage.html"), "UTF-8", "http://example.com/"); Element lastArticle = doc.getElementsByTag("article").last(); // Not disturb the user every time the application starts if there is not new update int currentVersion = (int) Main.applicationProperties.get("Version"); if (Integer.valueOf(lastArticle.id()) <= currentVersion && !showTheWindow) return; // Update is available or not? Platform.runLater(() -> { //--TopLabel if (Integer.valueOf(lastArticle.id()) > currentVersion) { window.setTitle("New update is available!"); topLabel.setText("New Update ->( " + lastArticle.id() + " )<- is available!"); } else { window.setTitle("You have the latest update!"); topLabel.setText("You have the latest update ->( " + currentVersion + " )<-"); } updatesInformationLabel.setText("Your current update is: ->( " + currentVersion + " )<-"); //Clear the textAreas textArea1.clear(); textArea2.clear(); // -- TextArea String style = "-fx-font-weight:bold; -fx-font-size:14; -fx-fill:black;"; doc.getElementsByTag("article").forEach(element -> { // Append the text to the textArea textArea1.appendText("\n\n-------------Start of Update (" + element.id() + ")-------------\n"); // Information textArea1.appendText("->Information: "); textArea1.setStyle(textArea1.getLength() - 13, textArea1.getLength() - 1, style.replace("black", "#202020")); textArea1.appendText(element.getElementsByClass("about").text() + "\n"); // Release Date textArea1.appendText("->Release Date: "); textArea1.setStyle(textArea1.getLength() - 14, textArea1.getLength() - 1, style.replace("black", "firebrick")); textArea1.appendText(element.getElementsByClass("releasedate").text() + "\n"); // Minimum JRE textArea1.appendText("->Minimum Java Version: "); textArea1.setStyle(textArea1.getLength() - 22, textArea1.getLength() - 1, style.replace("black", "orange")); textArea1.appendText(element.getElementsByClass("minJavaVersion").text() + "\n"); // ChangeLog textArea1.appendText("->ChangeLog:\n"); textArea1.setStyle(textArea1.getLength() - 11, textArea1.getLength() - 1, style.replace("black", "green")); final AtomicInteger counter = new AtomicInteger(-1); Arrays.asList(element.getElementsByClass("changelog").text().split("\\*")).forEach(el -> { if (counter.addAndGet(1) >= 1) { String s = "\t" + counter + ")"; textArea1.appendText(s); textArea1.setStyle(textArea1.getLength() - s.length(), textArea1.getLength() - 1, style); textArea1.appendText(el + "\n"); } }); }); textArea1.moveTo(textArea1.getLength()); textArea1.requestFollowCaret(); // -- TextArea 2 doc.getElementsByTag("section").forEach(section -> { // Append the text to the textArea textArea2.appendText("\n\n-------------Upcoming Features for XR3Player-------------\n\n"); // Information textArea2.appendText("->Coming:\n"); textArea2.setStyle(textArea2.getLength() - 8, textArea2.getLength() - 1, style.replace("black", "green")); final AtomicInteger counter = new AtomicInteger(-1); Arrays.asList(section.getElementById("info").text().split("\\*")).forEach(el -> { if (counter.addAndGet(1) >= 1) { String s = "\t" + counter + ")"; textArea2.appendText(s); textArea2.setStyle(textArea2.getLength() - s.length(), textArea2.getLength() - 1, style); textArea2.appendText(el + "\n"); } }); //Last Updated textArea2.appendText("->Last Updated: "); textArea2.setStyle(textArea2.getLength() - 14, textArea2.getLength() - 1, style.replace("black", "firebrick")); textArea2.appendText(section.getElementById("lastUpdated").text()); }); textArea2.moveTo(textArea2.getLength()); textArea2.requestFollowCaret(); }); //show? if (showTheWindow || Integer.valueOf(lastArticle.id()) > currentVersion) { download.setDisable(Integer.valueOf(lastArticle.id()) <= currentVersion); automaticUpdate.setDisable(download.isDisable()); show(); } } catch (IOException ex) { Platform.runLater(() -> ActionTool.showNotification("Error", "Trying to fetch update information a problem occured", Duration.millis(2500), NotificationType.ERROR)); logger.log(Level.WARNING, "", ex); } } /** * Calling this method to start the main Application which is XR3Player * */ public void startXR3PlayerUpdater() { String applicationName = "XR3PlayerUpdater"; // Start XR3Player Updater new Thread(() -> { String path = InfoTool.getBasePathForClass(Main.class); String[] applicationPath = { new File(path + applicationName + ".jar").getAbsolutePath() }; //Show message that application is restarting Platform.runLater(() -> ActionTool.showNotification("Starting " + applicationName, "Application Path:[ " + applicationPath[0] + " ]\n\tIf this takes more than 10 seconds either the computer is slow or it has failed....", Duration.seconds(25), NotificationType.INFORMATION)); try { //----Auto Update Button Platform.runLater(() -> automaticUpdate.setDisable(true)); //------------Export XR3PlayerUpdater ActionTool.copy(UpdateWindow.class.getResourceAsStream("/updater/" + applicationName + ".jar"), applicationPath[0]); //------------Wait until XR3Player is created File XR3Player = new File(applicationPath[0]); while (!XR3Player.exists()) { Thread.sleep(50); System.out.println("Waiting " + applicationName + " Jar to be created..."); } System.out.println(applicationName + " Path is : " + applicationPath[0]); //Create a process builder ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath[0], "45"); builder.redirectErrorStream(true); Process process = builder.start(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); // Wait n seconds PauseTransition pause = new PauseTransition(Duration.seconds(10)); pause.setOnFinished(f -> Platform.runLater(() -> ActionTool.showNotification("Starting " + applicationName + " failed", "\nApplication Path: [ " + applicationPath[0] + " ]\n\tTry to do it manually...", Duration.seconds(10), NotificationType.ERROR))); pause.play(); // Continuously Read Output to check if the main application started String line; while (process.isAlive()) while ( ( line = bufferedReader.readLine() ) != null) { System.out.println(line); if (line.isEmpty()) break; if (line.contains(applicationName + " Application Started")) System.exit(0); } } catch (IOException | InterruptedException ex) { Logger.getLogger(Main.class.getName()).log(Level.INFO, null, ex); // Show failed message Platform.runLater(() -> Platform.runLater(() -> ActionTool.showNotification("Starting " + applicationName + " failed", "\nApplication Path: [ " + applicationPath[0] + " ]\n\tTry to do it manually...", Duration.seconds(10), NotificationType.ERROR))); } //----Auto Update Button Platform.runLater(() -> automaticUpdate.setDisable(false)); }, "Start XR3Application Thread").start(); } /** * Show the Window */ public void show() { Platform.runLater(() -> { if (!window.isShowing()) window.show(); else window.requestFocus(); }); } /** * @return the window */ public Stage getWindow() { return window; } }