From a225f267cf9dac3357721621edf7b3d9763b29dd Mon Sep 17 00:00:00 2001 From: Drew Short Date: Wed, 23 Apr 2014 01:35:01 -0500 Subject: [PATCH] Started doing some work on the GUI. Added a markdown processor. Change the about file to be a markdown file. Got the about button to implement a parser and display a dialog. Included an example of a utility dialog that loads a remote website. --- pom.xml | 27 +++- src/main/java/com/sothr/imagetools/App.java | 85 ++++++----- .../java/com/sothr/imagetools/AppConfig.java | 12 +- .../documents/{about.info => about.md} | 2 +- src/main/resources/fxml/mainapp/MainApp.fxml | 45 +++--- .../scala/com/sothr/imagetools/Engine.scala | 2 +- .../ui/controller/AppController.scala | 137 +++++++++++++++--- 7 files changed, 223 insertions(+), 87 deletions(-) rename src/main/resources/documents/{about.info => about.md} (74%) diff --git a/pom.xml b/pom.xml index 2fde5c5..8a8f711 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,7 @@ 1.3.175 4.3.0.Final 2.6.6 + 2.2-cj-1.0 @@ -160,6 +161,11 @@ hibernate-c3p0 ${lib.hibernate.version} + + org.commonjava.googlecode.markdown4j + markdown4j + ${lib.markdown4j.version} + @@ -171,6 +177,7 @@ **/*.conf **/*.properties **/*.info + **/*.md @@ -180,6 +187,7 @@ **/*.conf **/*.properties **/*.info + **/*.md @@ -191,6 +199,7 @@ **/*.conf **/*.properties **/*.info + **/*.md @@ -200,6 +209,7 @@ **/*.conf **/*.properties **/*.info + **/*.md @@ -403,7 +413,8 @@ maven-antrun-plugin 1.4 - + + prepare process-resources @@ -423,6 +434,20 @@ run + + package + package + + + + + + + + + run + + diff --git a/src/main/java/com/sothr/imagetools/App.java b/src/main/java/com/sothr/imagetools/App.java index 9bfb010..39c4a2c 100644 --- a/src/main/java/com/sothr/imagetools/App.java +++ b/src/main/java/com/sothr/imagetools/App.java @@ -25,57 +25,62 @@ public class App extends Application public static void main( String[] args ) { - AppConfig.configureApp(); - try { - //try to run the UI - launch(args); - } catch (Exception ex) { - logger.error("A fatal error has occurred: ", ex); - //show popup about the error to the user then exit - } + AppConfig.configureApp(); + + try { + //try to run the UI + launch(args); + } catch (Exception ex) { + logger.error("A fatal error has occurred: ", ex); + //show popup about the error to the user then exit + } } @Override public void init() throws Exception{ - AppConfig.configureApp(); - logger = LoggerFactory.getLogger(this.getClass()); - logger.info("Initializing Image Tools"); - List parameters = this.getParameters().getRaw(); - logger.info(String.format("Application was called with '%s' parameters", parameters.toString())); - super.init(); + AppConfig.configureApp(); + logger = LoggerFactory.getLogger(this.getClass()); + logger.info("Initializing Image Tools"); + List parameters = this.getParameters().getRaw(); + logger.info(String.format("Application was called with '%s' parameters", parameters.toString())); + super.init(); } @Override public void start(Stage primaryStage) throws Exception { - logger.info("Image-Tools is starting"); - logger.info(String.format("Launching GUI with FXML file %s", MAINGUI_FXML)); - try { - Parent root = FXMLLoader.load(ResourceLoader.get().getResource(MAINGUI_FXML)); - primaryStage.setScene(new Scene(root)); - //config main scene - primaryStage.setTitle("Image Tools"); - primaryStage.setMinHeight(600.0); - primaryStage.setMinWidth(800.0); - primaryStage.setResizable(true); - //show main scene - primaryStage.show(); - } catch (IOException ioe) { - String message = String.format("Unable to load FXML file: %s", MAINGUI_FXML); - ImageToolsException ite = new ImageToolsException(message, ioe); - logger.error(message, ioe); - throw ite; - } catch (Exception ex) { - String message = "An unhandled exception was thrown by the GUI"; - ImageToolsException ite = new ImageToolsException(message, ex); - logger.error(message, ex); - throw ite; - } + logger.info("Image-Tools is starting"); + logger.info(String.format("Launching GUI with FXML file %s", MAINGUI_FXML)); + //store the primary stage globally for reference in popups and the like + AppConfig.setPrimaryStage(primaryStage); + try { + Parent root = FXMLLoader.load(ResourceLoader.get().getResource(MAINGUI_FXML)); + primaryStage.setScene(new Scene(root)); + //config main scene + primaryStage.setTitle("Image Tools"); + primaryStage.setMinHeight(600.0); + primaryStage.setMinWidth(800.0); + primaryStage.setResizable(true); + //show main scene + primaryStage.show(); + } catch (IOException ioe) { + String message = String.format("Unable to load FXML file: %s", MAINGUI_FXML); + ImageToolsException ite = new ImageToolsException(message, ioe); + logger.error(message, ioe); + throw ite; + } catch (Exception ex) { + String message = "An unhandled exception was thrown by the GUI"; + ImageToolsException ite = new ImageToolsException(message, ex); + logger.error(message, ex); + throw ite; + } } @Override public void stop() throws Exception { - logger.info("Image-Tools is shutting down"); - AppConfig.shutdown(); - super.stop(); + logger.info("Image-Tools is shutting down"); + AppConfig.shutdown(); + super.stop(); + //force the JVM to close + System.exit(0); } } diff --git a/src/main/java/com/sothr/imagetools/AppConfig.java b/src/main/java/com/sothr/imagetools/AppConfig.java index 9e89f16..f98d987 100644 --- a/src/main/java/com/sothr/imagetools/AppConfig.java +++ b/src/main/java/com/sothr/imagetools/AppConfig.java @@ -5,6 +5,7 @@ import com.sothr.imagetools.dao.HibernateUtil; import com.sothr.imagetools.util.ResourceLoader; import com.sothr.imagetools.util.PropertiesService; import com.sothr.imagetools.util.PropertiesEnum; +import javafx.stage.Stage; import net.sf.ehcache.CacheManager; import org.slf4j.LoggerFactory; @@ -23,21 +24,26 @@ public class AppConfig { private static Logger logger; public static CacheManager cacheManager; - //Logging defaults + // Logging defaults private static final String LOGSETTINGSFILE = "./logback.xml"; private static Boolean configuredLogging = false; - //Properties defaults + // Properties defaults private static final String DEFAULTPROPERTIESFILE = "application.conf"; private static final String USERPROPERTIESFILE = "user.conf"; private static Boolean loadedProperties = false; - //Cache defaults + // Cache defaults private static Boolean configuredCache = false; // General Akka Actor System private static ActorSystem appSystem = ActorSystem.create("ITActorSystem"); + // The Main App + private static Stage primaryStage = null; + public static Stage getPrimaryStage() { return primaryStage; } + public static void setPrimaryStage(Stage newPrimaryStage) { primaryStage = newPrimaryStage; } + public static ActorSystem getAppActorSystem() { return appSystem; } diff --git a/src/main/resources/documents/about.info b/src/main/resources/documents/about.md similarity index 74% rename from src/main/resources/documents/about.info rename to src/main/resources/documents/about.md index becd829..e69d508 100644 --- a/src/main/resources/documents/about.info +++ b/src/main/resources/documents/about.md @@ -1,4 +1,4 @@ -Image Tools Version: ${project.version} +**Image Tools Version: ${project.version}** This is a simple about script. It demonstrates loading the about text from a file. diff --git a/src/main/resources/fxml/mainapp/MainApp.fxml b/src/main/resources/fxml/mainapp/MainApp.fxml index 3156570..eff6ff7 100644 --- a/src/main/resources/fxml/mainapp/MainApp.fxml +++ b/src/main/resources/fxml/mainapp/MainApp.fxml @@ -4,24 +4,27 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/scala/com/sothr/imagetools/Engine.scala b/src/main/scala/com/sothr/imagetools/Engine.scala index 86b5936..20c5eef 100644 --- a/src/main/scala/com/sothr/imagetools/Engine.scala +++ b/src/main/scala/com/sothr/imagetools/Engine.scala @@ -10,7 +10,7 @@ import akka.actor.{ActorRef, ActorSystem, ActorLogging, Actor} /** * Created by drew on 1/26/14. */ -abstract class Engine extends Logging{ +abstract class Engine extends Logging { val system = ActorSystem("EngineActorSystem") val imageFilter:ImageFilter = new ImageFilter() val imageCache = AppConfig.cacheManager.getCache("images") diff --git a/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala b/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala index 4601f85..cd1c545 100644 --- a/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala +++ b/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala @@ -2,60 +2,157 @@ package com.sothr.imagetools.ui.controller import javafx.fxml.FXML import javafx.event.ActionEvent -import org.slf4j.LoggerFactory -import org.slf4j.Logger import javafx.stage.{StageStyle, Stage} import javafx.scene.Scene import javafx.scene.Group -import javafx.scene.text.Text -import java.io.{IOException, File} +import javafx.scene.text.{TextAlignment, Text} +import java.io.IOException import java.util.Scanner import com.sothr.imagetools.util.ResourceLoader -import java.net.URL +import grizzled.slf4j.Logging +import javafx.scene.web.WebView +import org.markdown4j.Markdown4jProcessor /** * Created by drew on 12/31/13. */ -class AppController { +class AppController extends Logging { - val logger:Logger = LoggerFactory.getLogger(this.getClass) + //val logger:Logger = LoggerFactory.getLogger(this.getClass) //Define controls @FXML var rootMenuBar : javafx.scene.control.MenuBar = null //region MenuItem Actions + @FXML + def helpAction(event:ActionEvent) = { + showExternalHTMLUtilityDialog("http://www.sothr.com") + } + @FXML def aboutAction(event:ActionEvent) = { - logger.debug("Displaying about screen") + debug("Displaying about screen") var aboutMessage = "Simple About Message" try { - aboutMessage = new Scanner(ResourceLoader.get().getResourceStream("documents/about")).useDelimiter("\\A").next() + + val scanner = new Scanner(ResourceLoader.get().getResourceStream("documents/about.md")) + aboutMessage = "" + while (scanner.hasNextLine) { + aboutMessage += scanner.nextLine().trim() + "\n" + } + + debug(s"Parsed About Message: '$aboutMessage'") + } catch { case ioe:IOException => - logger.error("Unable to read about file") + error("Unable to read about file") } + showMarkdownUtilityDialog("About", aboutMessage, 400.0, 300.0) + debug("Showing About Dialog") + } + + @FXML + def closeAction(event:ActionEvent ) = { + debug("Closing application from the menu bar") + val stage:Stage = this.rootMenuBar.getScene.getWindow.asInstanceOf[Stage] + stage.close() + } + + //endregion + + //todo: include a templating engine for rendering information + + //todo: show a dialog that is rendered from markdown content + def showMarkdownUtilityDialog(title:String, markdown:String, width:Double = 800.0, height:Double = 600.0) = { + val htmlBody = new Markdown4jProcessor().process(markdown) + showHTMLUtilityDialog(title, htmlBody, width, height) + } + + /** + * Render HTML content to a utility dialog. No input or output, just raw rendered content through a webkit engine. + * + * @param title + * @param htmlBody + * @param width + * @param height + */ + def showHTMLUtilityDialog(title:String, htmlBody:String, width:Double = 800.0, height:Double = 600.0) = { val dialog:Stage = new Stage() dialog.initStyle(StageStyle.UTILITY) - val parent:Group = new Group(); - parent.getChildren.add(new Text(25, 25, aboutMessage)) + val parent:Group = new Group() + + //setup the HTML view + val htmlView = new WebView + htmlView.getEngine.loadContent(htmlBody) + htmlView.setMinWidth(width) + htmlView.setMinHeight(height) + htmlView.setPrefWidth(width) + htmlView.setPrefHeight(height) + parent.getChildren.add(htmlView) + val scene:Scene = new Scene(parent) dialog.setScene(scene) dialog.setResizable(false) - dialog.setMinHeight(400.0) - dialog.setMinWidth(400.0) + dialog.setTitle(title) dialog.show() } - @FXML - def closeAction(event:ActionEvent ) = { - logger.debug("Closing application from the menu bar") - val stage:Stage = this.rootMenuBar.getScene.getWindow.asInstanceOf[Stage] - stage.close() + def showExternalHTMLUtilityDialog(url:String) = { + val dialog:Stage = new Stage() + dialog.initStyle(StageStyle.UTILITY) + val parent:Group = new Group() + + //setup the HTML view + val htmlView = new WebView + htmlView.getEngine.load(url) + //htmlView.setMinWidth(width) + //htmlView.setMinHeight(height) + //htmlView.setPrefWidth(width) + //htmlView.setPrefHeight(height) + parent.getChildren.add(htmlView) + + val scene:Scene = new Scene(parent) + dialog.setScene(scene) + dialog.setResizable(false) + dialog.setTitle(htmlView.getEngine.getTitle) + dialog.show() } - //endregion + /** + * Show a plain text utility dialog + * + * @param message + * @param wrapWidth + * @param alignment + */ + def showUtilityDialog(title:String, + message:String, + wrapWidth:Double=300.0, + xOffset:Double = 25.0, + yOffset:Double = 25.0, + alignment:TextAlignment=TextAlignment.JUSTIFY) = { + val dialog:Stage = new Stage() + dialog.initStyle(StageStyle.UTILITY) + val parent:Group = new Group() + + // fill the text box + val messageText = new Text() + messageText.setText(message) + messageText.setWrappingWidth(wrapWidth) + messageText.setX(xOffset) + messageText.setY(yOffset) + messageText.setTextAlignment(TextAlignment.JUSTIFY) + + parent.getChildren.add(messageText) + val scene:Scene = new Scene(parent) + dialog.setScene(scene) + dialog.setResizable(false) + dialog.setMinWidth(wrapWidth+xOffset*2) + dialog.setTitle(title) + dialog.show() + } def print():String = { return "This method works"