Browse Source

Working progress bar and progress label implementation

master
Drew Short 10 years ago
parent
commit
e72b94281e
  1. 116
      gui/src/main/resources/fxml/mainapp/MainApp.fxml
  2. 153
      gui/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala

116
gui/src/main/resources/fxml/mainapp/MainApp.fxml

@ -1,91 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL --> <!--suppress ALL -->
<?import java.lang.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?> <?import javafx.geometry.*?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<AnchorPane fx:id="rootPane" minHeight="600.0" minWidth="1024.0" prefHeight="600.0" prefWidth="1024.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.sothr.imagetools.ui.controller.AppController">
<AnchorPane fx:id="rootPane" minHeight="600.0" minWidth="1024.0" prefHeight="600.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.sothr.imagetools.ui.controller.AppController">
<children> <children>
<MenuBar fx:id="rootMenuBar" minWidth="-Infinity" prefHeight="30.0" prefWidth="600.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<MenuBar fx:id="rootMenuBar" minWidth="-Infinity" prefHeight="30.0" prefWidth="600.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<menus> <menus>
<Menu mnemonicParsing="false" text="File"> <Menu mnemonicParsing="false" text="File">
<items> <items>
<MenuItem fx:id="" mnemonicParsing="false" onAction="#closeAction" text="Close"/>
<MenuItem fx:id="" mnemonicParsing="false" onAction="#closeAction" text="Close" />
</items> </items>
</Menu> </Menu>
<Menu mnemonicParsing="false" text="Edit"> <Menu mnemonicParsing="false" text="Edit">
<items> <items>
<MenuItem mnemonicParsing="false" text="Settings"/>
<MenuItem mnemonicParsing="false" text="Settings" />
</items> </items>
</Menu> </Menu>
<Menu mnemonicParsing="false" text="Help"> <Menu mnemonicParsing="false" text="Help">
<items> <items>
<MenuItem mnemonicParsing="false" onAction="#aboutAction" text="About"/>
<MenuItem mnemonicParsing="false" onAction="#helpAction" text="Help Site"/>
<MenuItem mnemonicParsing="false" onAction="#aboutAction" text="About" />
<MenuItem mnemonicParsing="false" onAction="#helpAction" text="Help Site" />
</items> </items>
</Menu> </Menu>
</menus> </menus>
</MenuBar> </MenuBar>
<VBox id="VBox" alignment="CENTER" spacing="5.0" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="30.0">
<VBox id="VBox" alignment="CENTER" spacing="5.0" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="30.0">
<children> <children>
<SplitPane dividerPositions="0.2181996086105675" focusTraversable="true" prefHeight="569.0" prefWidth="1024.0"
visible="true" VBox.vgrow="ALWAYS">
<SplitPane dividerPositions="0.2181996086105675" focusTraversable="true" prefHeight="569.0" prefWidth="1024.0" visible="true" VBox.vgrow="ALWAYS">
<items> <items>
<TabPane maxWidth="220.0" minHeight="0.0" minWidth="220.0" prefHeight="567.0" prefWidth="220.0"
tabClosingPolicy="UNAVAILABLE">
<TabPane maxWidth="220.0" minHeight="0.0" minWidth="220.0" prefHeight="567.0" prefWidth="220.0" tabClosingPolicy="UNAVAILABLE">
<tabs> <tabs>
<Tab closable="false" text="Folders"> <Tab closable="false" text="Folders">
<content> <content>
<BorderPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="200.0"
prefWidth="200.0">
<BorderPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="200.0" prefWidth="200.0">
<top> <top>
<Button maxWidth="1.7976931348623157E308" minWidth="200.0" mnemonicParsing="false"
onAction="#browseFolders" text="Browse" BorderPane.alignment="CENTER"/>
<Button maxWidth="1.7976931348623157E308" minWidth="200.0" mnemonicParsing="false" onAction="#browseFolders" text="Browse" BorderPane.alignment="CENTER" />
</top> </top>
<center> <center>
<FlowPane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER"> <FlowPane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children> <children>
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="210.0"
text="Selected Folder:">
<Label maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="210.0" text="Selected Folder:">
<padding> <padding>
<Insets left="5.0" right="5.0"/>
<Insets left="5.0" right="5.0" />
</padding> </padding>
</Label> </Label>
<Label fx:id="selectedDirectoryLabel" alignment="TOP_LEFT" lineSpacing="2.0"
maxHeight="1.7976931348623157E308" maxWidth="210.0" minWidth="210.0"
prefWidth="210.0" text="&lt;SELECTED&gt;" wrapText="true">
<Label fx:id="selectedDirectoryLabel" alignment="TOP_LEFT" lineSpacing="2.0" maxHeight="1.7976931348623157E308" maxWidth="210.0" minWidth="210.0" prefWidth="210.0" text="&lt;SELECTED&gt;" wrapText="true">
<font> <font>
<Font name="System Bold" size="12.0"/>
<Font name="System Bold" size="12.0" />
</font> </font>
<padding> <padding>
<Insets left="5.0" right="5.0"/>
<Insets left="5.0" right="5.0" />
</padding> </padding>
</Label> </Label>
</children> </children>
</FlowPane> </FlowPane>
</center> </center>
<bottom> <bottom>
<FlowPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="60.0"
prefWidth="220.0" BorderPane.alignment="CENTER">
<FlowPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="60.0" prefWidth="220.0" BorderPane.alignment="CENTER">
<children> <children>
<Button maxWidth="1.7976931348623157E308" minWidth="220.0" mnemonicParsing="false"
onAction="#showAllImages" text="Show All Images">
<Button maxWidth="1.7976931348623157E308" minWidth="220.0" mnemonicParsing="false" onAction="#showAllImages" text="Show All Images">
<FlowPane.margin> <FlowPane.margin>
<Insets bottom="5.0"/>
<Insets bottom="5.0" />
</FlowPane.margin> </FlowPane.margin>
</Button> </Button>
<Button maxWidth="200.0" minWidth="220.0" mnemonicParsing="false"
onAction="#showSimilarImages" text="Show Similar Images"/>
<Button maxWidth="200.0" minWidth="220.0" mnemonicParsing="false" onAction="#showSimilarImages" text="Show Similar Images" />
</children> </children>
</FlowPane> </FlowPane>
</bottom> </bottom>
<padding> <padding>
<Insets bottom="5.0" top="5.0"/>
<Insets bottom="5.0" top="5.0" />
</padding> </padding>
</BorderPane> </BorderPane>
</content> </content>
@ -94,27 +84,17 @@
<content> <content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0"> <AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children> <children>
<AnchorPane id="AnchorPane" maxHeight="50.0" prefHeight="50.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="5.0">
<AnchorPane id="AnchorPane" maxHeight="50.0" prefHeight="50.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="5.0">
<children> <children>
<TextField layoutY="0.0" prefWidth="200.0" text="" AnchorPane.leftAnchor="20.0"
AnchorPane.rightAnchor="20.0"/>
<Button layoutY="27.0" mnemonicParsing="false" prefWidth="192.0" text="Filter"
AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0"/>
<TextField layoutY="0.0" prefWidth="200.0" text="" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" />
<Button layoutY="27.0" mnemonicParsing="false" prefWidth="192.0" text="Filter" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" />
</children> </children>
</AnchorPane> </AnchorPane>
<ListView fx:id="tagListView" prefHeight="385.0" prefWidth="198.0"
AnchorPane.bottomAnchor="60.0" AnchorPane.leftAnchor="10.0"
AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="60.0"/>
<AnchorPane id="AnchorPane" prefWidth="192.0" AnchorPane.bottomAnchor="5.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<ListView fx:id="tagListView" prefHeight="385.0" prefWidth="198.0" AnchorPane.bottomAnchor="60.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="60.0" />
<AnchorPane id="AnchorPane" prefWidth="192.0" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children> <children>
<Button layoutY="2.0" mnemonicParsing="false" prefWidth="192.0"
text="View All Images In Tags" AnchorPane.leftAnchor="20.0"
AnchorPane.rightAnchor="20.0"/>
<Button layoutY="28.0" mnemonicParsing="false" prefWidth="192.0"
text="Search For Similarities In Tags" AnchorPane.leftAnchor="20.0"
AnchorPane.rightAnchor="20.0"/>
<Button layoutY="2.0" mnemonicParsing="false" prefWidth="192.0" text="View All Images In Tags" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" />
<Button layoutY="28.0" mnemonicParsing="false" prefWidth="192.0" text="Search For Similarities In Tags" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" />
</children> </children>
</AnchorPane> </AnchorPane>
</children> </children>
@ -127,25 +107,20 @@
<children> <children>
<ToolBar maxHeight="30.0" minHeight="30.0" prefHeight="30.0" VBox.vgrow="ALWAYS"> <ToolBar maxHeight="30.0" minHeight="30.0" prefHeight="30.0" VBox.vgrow="ALWAYS">
<items> <items>
<Label text="Currect Directory:"/>
<Separator orientation="VERTICAL" prefHeight="200.0"/>
<Label text="&lt;CURRENT DIRECTORY&gt;"/>
<Label text="Currect Directory:" />
<Separator orientation="VERTICAL" prefHeight="200.0" />
<Label text="&lt;CURRENT DIRECTORY&gt;" />
</items> </items>
<VBox.margin> <VBox.margin>
<Insets bottom="-5.0"/>
<Insets bottom="-5.0" />
</VBox.margin> </VBox.margin>
</ToolBar> </ToolBar>
<ScrollPane id="ScrollPane" fitToHeight="true" fitToWidth="true" minWidth="600.0" pannable="false"
prefViewportHeight="567.0" prefViewportWidth="766.0" vbarPolicy="AS_NEEDED"
VBox.vgrow="ALWAYS">
<ScrollPane id="ScrollPane" fitToHeight="true" fitToWidth="true" minWidth="600.0" pannable="false" prefViewportHeight="567.0" prefViewportWidth="766.0" vbarPolicy="AS_NEEDED" VBox.vgrow="ALWAYS">
<content> <content>
<TilePane fx:id="imageTilePane" hgap="5.0" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" minWidth="-1.0" prefColumns="6" prefHeight="-1.0"
prefTileHeight="160.0" prefTileWidth="160.0" prefWidth="-1.0" tileAlignment="TOP_LEFT"
vgap="5.0"/>
<TilePane fx:id="imageTilePane" hgap="5.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="-1.0" prefColumns="6" prefHeight="-1.0" prefTileHeight="160.0" prefTileWidth="160.0" prefWidth="-1.0" tileAlignment="TOP_LEFT" vgap="5.0" />
</content> </content>
<VBox.margin> <VBox.margin>
<Insets/>
<Insets />
</VBox.margin> </VBox.margin>
</ScrollPane> </ScrollPane>
</children> </children>
@ -154,14 +129,13 @@
</SplitPane> </SplitPane>
</children> </children>
</VBox> </VBox>
<ToolBar maxHeight="30.0" maxWidth="1.7976931348623157E308" minHeight="30.0" orientation="HORIZONTAL"
prefHeight="30.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<ToolBar maxHeight="30.0" maxWidth="1.7976931348623157E308" minHeight="30.0" orientation="HORIZONTAL" prefHeight="30.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<items> <items>
<Label text="Progress:"/>
<Separator orientation="VERTICAL" prefHeight="200.0"/>
<ProgressBar prefWidth="200.0" progress="0.0"/>
<Separator orientation="VERTICAL" prefHeight="200.0"/>
<Label text="&lt;PROGRESS INFORMATION&gt;"/>
<Label text="Progress:" />
<Separator orientation="VERTICAL" prefHeight="200.0" />
<ProgressBar fx:id="progressBar" prefWidth="200.0" progress="0.0" />
<Separator orientation="VERTICAL" prefHeight="200.0" />
<Label fx:id="progressLabel" text="&lt;PROGRESS INFORMATION&gt;" />
</items> </items>
</ToolBar> </ToolBar>
</children> </children>

153
gui/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala

@ -1,21 +1,29 @@
package com.sothr.imagetools.ui.controller package com.sothr.imagetools.ui.controller
import java.io.{File, IOException} import java.io.{File, IOException}
import java.util
import java.util.ArrayList
import java.util.Scanner import java.util.Scanner
import javafx.application.Platform
import javafx.event.ActionEvent import javafx.event.ActionEvent
import javafx.fxml.FXML import javafx.fxml.FXML
import javafx.scene.control.{Label, ProgressBar}
import javafx.scene.text.{Text, TextAlignment} import javafx.scene.text.{Text, TextAlignment}
import javafx.scene.web.WebView import javafx.scene.web.WebView
import javafx.scene.{Group, Node, Scene} import javafx.scene.{Group, Node, Scene}
import javafx.stage.{DirectoryChooser, Stage, StageStyle} import javafx.stage.{DirectoryChooser, Stage, StageStyle}
import akka.actor._
import com.sothr.imagetools.engine.image.{SimilarImages, Image}
import com.sothr.imagetools.engine.util.{PropertiesService, ResourceLoader} import com.sothr.imagetools.engine.util.{PropertiesService, ResourceLoader}
import com.sothr.imagetools.engine.{ConcurrentEngine, Engine}
import com.sothr.imagetools.engine._
import com.sothr.imagetools.ui.component.ImageTileFactory import com.sothr.imagetools.ui.component.ImageTileFactory
import grizzled.slf4j.Logging import grizzled.slf4j.Logging
import org.markdown4j.Markdown4jProcessor import org.markdown4j.Markdown4jProcessor
import scala.concurrent._
import scala.util.{Failure, Success}
import ExecutionContext.Implicits.global
/** /**
* Main Application controller * Main Application controller
* *
@ -31,6 +39,10 @@ class AppController extends Logging {
// Labels // Labels
@FXML var selectedDirectoryLabel: javafx.scene.control.Label = null @FXML var selectedDirectoryLabel: javafx.scene.control.Label = null
@FXML var progressLabel: javafx.scene.control.Label = null
// Others
@FXML var progressBar: javafx.scene.control.ProgressBar = null
// Engine // Engine
val engine: Engine = new ConcurrentEngine() val engine: Engine = new ConcurrentEngine()
@ -42,6 +54,18 @@ class AppController extends Logging {
if (PropertiesService.has("lastPath")) { if (PropertiesService.has("lastPath")) {
currentDirectory = PropertiesService.get("lastPath", ".") currentDirectory = PropertiesService.get("lastPath", ".")
selectedDirectoryLabel.setText(PropertiesService.get("lastPath", "")) selectedDirectoryLabel.setText(PropertiesService.get("lastPath", ""))
//setup the engine listener
val system: ActorSystem = AppConfig.getAppActorSystem
val guiListenerProps: Props = Props.create(classOf[GUIEngineListener])
val guiListener: ActorRef = system.actorOf(guiListenerProps)
// configure the listener
guiListener ! SetupListener(progressBar, progressLabel)
// tell the engine to use our listener
this.engine.setProcessedListener(guiListener)
this.engine.setSimilarityListener(guiListener)
// Initialize the progress label
guiListener ! SubmitMessage("Initialized System... Ready!")
} }
//test //test
@ -95,6 +119,10 @@ class AppController extends Logging {
stage.close() stage.close()
} }
//endregion
//region buttons
@FXML @FXML
def browseFolders(event: ActionEvent) = { def browseFolders(event: ActionEvent) = {
val chooser = new DirectoryChooser() val chooser = new DirectoryChooser()
@ -113,24 +141,51 @@ class AppController extends Logging {
@FXML @FXML
def showAllImages(event: ActionEvent) = { def showAllImages(event: ActionEvent) = {
imageTilePane.getChildren.setAll(new util.ArrayList[Node]())
val images = engine.getImagesForDirectory(currentDirectory)
info(s"Displaying ${images.length} images")
for (image <- images) {
debug(s"Adding image ${image.toString} to app")
imageTilePane.getChildren.add(ImageTileFactory.get(image))
imageTilePane.getChildren.setAll(new ArrayList[Node]())
val f: Future[List[Image]] = Future {
engine.getImagesForDirectory(currentDirectory)
}
f onComplete {
case Success(images) =>
info(s"Displaying ${images.length} images")
// This is used so that JavaFX updates on the proper thread
// This is important since UI updates can only happen on that thread
Platform.runLater(new Runnable() {
override def run() {
for (image <- images) {
debug(s"Adding image ${image.toString} to app")
imageTilePane.getChildren.add(ImageTileFactory.get(image))
}
}
})
case Failure(t) =>
error("An Error Occurred", t)
} }
} }
@FXML @FXML
def showSimilarImages(event: ActionEvent) = { def showSimilarImages(event: ActionEvent) = {
imageTilePane.getChildren.setAll(new util.ArrayList[Node]())
val similarImages = engine.getSimilarImagesForDirectory(currentDirectory)
info(s"Displaying ${similarImages.length} similar images")
for (similarImage <- similarImages) {
debug(s"Adding similar images ${similarImage.rootImage.toString} to app")
imageTilePane.getChildren.add(ImageTileFactory.get(similarImage.rootImage))
similarImage.similarImages.foreach(image => imageTilePane.getChildren.add(ImageTileFactory.get(image)))
imageTilePane.getChildren.setAll(new ArrayList[Node]())
val f: Future[List[SimilarImages]] = Future {
engine.getSimilarImagesForDirectory(currentDirectory)
}
f onComplete {
case Success(similarImages) =>
info(s"Displaying ${similarImages.length} similar images")
Platform.runLater(new Runnable() {
override def run() {
for (similarImage <- similarImages) {
debug(s"Adding similar images ${similarImage.rootImage.toString} to app")
imageTilePane.getChildren.add(ImageTileFactory.get(similarImage.rootImage))
similarImage.similarImages.foreach(image => imageTilePane.getChildren.add(ImageTileFactory.get(image)))
}
}
})
case Failure(t) =>
error("An Error Occurred", t)
} }
} }
@ -232,3 +287,71 @@ class AppController extends Logging {
"This method works" "This method works"
} }
} }
//region EngineListener
case class SetupListener(progressBar: ProgressBar, progressLabel: Label)
/**
* Actor for logging output information
*/
class GUIEngineListener extends EngineListener with ActorLogging {
var progressBar: javafx.scene.control.ProgressBar = null
var progressLabel: javafx.scene.control.Label = null
var isStarted = false
var isFinished = false
override def receive: Actor.Receive = {
case command: SetupListener => setupListener(command)
case command: SubmitMessage => handleMessage(command)
case command: ScannedFileCount => handleScannedFileCount(command)
case command: ComparedFileCount => handleComparedFileCount(command)
case _ => log.info("received unknown message")
}
def setupListener(command: SetupListener) = {
this.progressBar = command.progressBar
this.progressLabel = command.progressLabel
}
override def handleComparedFileCount(command: ComparedFileCount): Unit = {
Platform.runLater(new Runnable() {
override def run(): Unit = {
if (command.message != null) {
log.debug(command.message)
progressLabel.setText(command.message)
} else {
progressLabel.setText(s"Processed ${command.count}/${command.total}")
}
log.debug("Processed {}/{}", command.count, command.total)
progressBar.setProgress(command.count.toFloat/command.total)
}
})
}
override def handleScannedFileCount(command: ScannedFileCount): Unit = {
Platform.runLater(new Runnable() {
override def run(): Unit = {
if (command.message != null) {
log.debug(command.message)
progressLabel.setText(command.message)
} else {
progressLabel.setText(s"Scanned ${command.count}/${command.total} For Similarities")
}
log.debug("Scanned {}/{} For Similarities", command.count, command.total)
progressBar.setProgress(command.count.toFloat/command.total)
}
})
}
override def handleMessage(command: SubmitMessage): Unit = {
Platform.runLater(new Runnable() {
override def run(): Unit = {
log.debug(command.message)
progressLabel.setText(command.message)
}
})
}
}
//endregion
Loading…
Cancel
Save