Browse Source

Working single and multi delete for files.

Laid the groundwork for other actions.
Started working on a logger for searches to update the GUI as necessary.
master
Drew Short 10 years ago
parent
commit
29bcda07ed
  1. 7
      engine/src/main/java/com/sothr/imagetools/engine/AppConfig.java
  2. 4
      engine/src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala
  3. 22
      engine/src/main/scala/com/sothr/imagetools/engine/Engine.scala
  4. 7
      engine/src/main/scala/com/sothr/imagetools/engine/dao/ImageDAO.scala
  5. 21
      engine/src/main/scala/com/sothr/imagetools/engine/image/ImageService.scala
  6. 11
      gui/src/main/java/com/sothr/imagetools/ui/App.java
  7. 73
      gui/src/main/scala/com/sothr/imagetools/ui/component/ImageTilePane.scala
  8. 2
      gui/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala

7
engine/src/main/java/com/sothr/imagetools/engine/AppConfig.java

@ -9,6 +9,7 @@ import ch.qos.logback.core.util.StatusPrinter;
import com.sothr.imagetools.engine.dao.HibernateUtil; import com.sothr.imagetools.engine.dao.HibernateUtil;
import com.sothr.imagetools.engine.util.PropertiesService; import com.sothr.imagetools.engine.util.PropertiesService;
import com.sothr.imagetools.engine.util.ResourceLoader; import com.sothr.imagetools.engine.util.ResourceLoader;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage; import javafx.stage.Stage;
import net.sf.ehcache.CacheManager; import net.sf.ehcache.CacheManager;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -46,6 +47,12 @@ public class AppConfig {
primaryStage = newPrimaryStage; primaryStage = newPrimaryStage;
} }
public static FXMLLoader fxmlLoader = null;
public static FXMLLoader getFxmlLoader() { return fxmlLoader; }
public static void setFxmlLoader(FXMLLoader loader) { fxmlLoader = loader; }
public static ActorSystem getAppActorSystem() { public static ActorSystem getAppActorSystem() {
return appSystem; return appSystem;
} }

4
engine/src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala

@ -19,6 +19,10 @@ class ConcurrentEngine extends Engine with grizzled.slf4j.Logging {
val engineSimilarityController = system.actorOf(Props[ConcurrentEngineSimilarityController], name = "EngineSimilarityController") val engineSimilarityController = system.actorOf(Props[ConcurrentEngineSimilarityController], name = "EngineSimilarityController")
implicit val timeout = Timeout(30, TimeUnit.SECONDS) implicit val timeout = Timeout(30, TimeUnit.SECONDS)
override def setSearchedListener(listenerRef: ActorRef) = {
}
override def setProcessedListener(listenerRef: ActorRef) = { override def setProcessedListener(listenerRef: ActorRef) = {
engineProcessingController ! SetNewListener(listenerRef) engineProcessingController ! SetNewListener(listenerRef)
} }

22
engine/src/main/scala/com/sothr/imagetools/engine/Engine.scala

@ -2,8 +2,8 @@ package com.sothr.imagetools.engine
import java.io.File import java.io.File
import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem}
import com.sothr.imagetools.engine.image.{Image, ImageFilter, SimilarImages}
import akka.actor._
import com.sothr.imagetools.engine.image.{ImageService, Image, ImageFilter, SimilarImages}
import com.sothr.imagetools.engine.util.DirectoryFilter import com.sothr.imagetools.engine.util.DirectoryFilter
import grizzled.slf4j.Logging import grizzled.slf4j.Logging
@ -19,6 +19,14 @@ abstract class Engine extends Logging {
val imageFilter: ImageFilter = new ImageFilter() val imageFilter: ImageFilter = new ImageFilter()
val imageCache = AppConfig.cacheManager.getCache("images") val imageCache = AppConfig.cacheManager.getCache("images")
//file search listener
var searchedListener = system.actorOf(Props[DefaultLoggingEngineListener],
name = "SearchedEngineListener")
def setSearchedListener(listenerRef: ActorRef) = {
this.searchedListener = listenerRef
}
def setProcessedListener(listenerType: ActorRef) def setProcessedListener(listenerType: ActorRef)
def setSimilarityListener(listenerType: ActorRef) def setSimilarityListener(listenerType: ActorRef)
@ -55,6 +63,16 @@ abstract class Engine extends Logging {
* Get all similar images for a directory with hashes * Get all similar images for a directory with hashes
*/ */
def getSimilarImagesForDirectory(directoryPath: String, recursive: Boolean = false, recursiveDepth: Int = 500): List[SimilarImages] def getSimilarImagesForDirectory(directoryPath: String, recursive: Boolean = false, recursiveDepth: Int = 500): List[SimilarImages]
def deleteImage(image: Image): Unit = {
ImageService.deleteImage(image)
}
def deleteImages(images: List[Image]): Unit = {
for (image <- images) {
deleteImage(image)
}
}
} }
case class SubmitMessage(message: String) case class SubmitMessage(message: String)

7
engine/src/main/scala/com/sothr/imagetools/engine/dao/ImageDAO.scala

@ -34,4 +34,11 @@ class ImageDAO {
session.getTransaction.commit() session.getTransaction.commit()
} }
def delete(image: Image) = {
val session: Session = sessionFactory.getCurrentSession
session.getTransaction.begin()
session.delete(image)
session.getTransaction.commit()
}
} }

21
engine/src/main/scala/com/sothr/imagetools/engine/image/ImageService.scala

@ -11,6 +11,7 @@ import com.sothr.imagetools.engine.util.{PropertiesService, PropertyEnum}
import grizzled.slf4j.Logging import grizzled.slf4j.Logging
import net.coobird.thumbnailator.Thumbnails import net.coobird.thumbnailator.Thumbnails
import net.sf.ehcache.Element import net.sf.ehcache.Element
import org.hibernate.HibernateException
object ImageService extends Logging { object ImageService extends Logging {
@ -73,12 +74,28 @@ object ImageService extends Logging {
return saveImage(image) return saveImage(image)
} }
} catch { } catch {
case ioe: IOException => error(s"Error processing ${file.getAbsolutePath}", ioe)
case ex: Exception => error(s"Error processing ${file.getAbsolutePath}", ex)
case ioe: IOException => error(s"Error processing ${file.getAbsolutePath}... ${ioe.getMessage}")
case ex: Exception => error(s"Error processing ${file.getAbsolutePath}... ${ex.getMessage}", ex)
} }
null null
} }
def deleteImage(image: Image) = {
debug(s"Attempting to delete all traces of image: ${image.getImagePath}")
try {
val imageFile = new File(image.imagePath)
//try to delete the file
imageFile.delete()
//purge the file from the database and cache
this.imageCache.remove(imageFile.getAbsolutePath)
this.imageDAO.delete(image)
} catch {
case se: SecurityException => error(s"Unable to delete file: ${image.getImagePath} due to a security exception", se)
case ise: IllegalStateException => error(s"Unable to delete file: ${image.getImagePath} due to an illegal state exception", ise)
case he: HibernateException => error(s"Unable to delete file: ${image.getImagePath} due to a hibernate exception", he)
}
}
def calculateThumbPath(md5: String): String = { def calculateThumbPath(md5: String): String = {
//break the path down into 4 char parts //break the path down into 4 char parts
val subPath = md5.substring(0, 3) val subPath = md5.substring(0, 3)

11
gui/src/main/java/com/sothr/imagetools/ui/App.java

@ -3,8 +3,10 @@ package com.sothr.imagetools.ui;
import com.sothr.imagetools.engine.AppConfig; import com.sothr.imagetools.engine.AppConfig;
import com.sothr.imagetools.engine.errors.ImageToolsException; import com.sothr.imagetools.engine.errors.ImageToolsException;
import com.sothr.imagetools.engine.util.ResourceLoader; import com.sothr.imagetools.engine.util.ResourceLoader;
import com.sothr.imagetools.ui.controller.AppController;
import javafx.application.Application; import javafx.application.Application;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.fxml.JavaFXBuilderFactory;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -12,6 +14,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.List; import java.util.List;
/** /**
@ -52,7 +55,13 @@ public class App extends Application {
//store the primary stage globally for reference in popups and the like //store the primary stage globally for reference in popups and the like
AppConfig.setPrimaryStage(primaryStage); AppConfig.setPrimaryStage(primaryStage);
try { try {
Parent root = FXMLLoader.load(ResourceLoader.get().getResource(MAINGUI_FXML));
FXMLLoader loader = new FXMLLoader();
URL location = ResourceLoader.get().getResource(MAINGUI_FXML);
loader.setLocation(location);
loader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = loader.load(location.openStream());
//save the primary controller
AppConfig.setFxmlLoader(loader);
primaryStage.setScene(new Scene(root)); primaryStage.setScene(new Scene(root));
//config main scene //config main scene
primaryStage.setTitle("Image Tools"); primaryStage.setTitle("Image Tools");

73
gui/src/main/scala/com/sothr/imagetools/ui/component/ImageTilePane.scala

@ -1,6 +1,7 @@
package com.sothr.imagetools.ui.component package com.sothr.imagetools.ui.component
import java.util import java.util
import javafx.application.Platform
import javafx.collections.{ModifiableObservableListBase, ObservableList} import javafx.collections.{ModifiableObservableListBase, ObservableList}
import javafx.event.{ActionEvent, EventHandler} import javafx.event.{ActionEvent, EventHandler}
import javafx.geometry.Side import javafx.geometry.Side
@ -10,21 +11,22 @@ import javafx.scene.layout._
import javafx.scene.paint.Color import javafx.scene.paint.Color
import javafx.scene.Node import javafx.scene.Node
import scala.concurrent._
import ExecutionContext.Implicits.global
import com.sothr.imagetools.engine.AppConfig
import com.sothr.imagetools.ui.controller.AppController
import grizzled.slf4j.Logging import grizzled.slf4j.Logging
import scala.util.{Failure, Success}
/** /**
* Custom Tile Pane with a multi selection model * Custom Tile Pane with a multi selection model
* *
* Created by drew on 8/29/14. * Created by drew on 8/29/14.
*/ */
class ImageTilePane extends TilePane with Logging { class ImageTilePane extends TilePane with Logging {
val selectionModel = new ImageTilePaneSelectionModel(this)
//this.setOnContextMenuRequested(new EventHandler[ContextMenuEvent] {
// override def handle(event: ContextMenuEvent): Unit = {
// handleContextMenu(event)
// }
//})
val selectionModel = new ImageTilePaneSelectionModel[ImageTile](this)
def handleContextMenu(event: ContextMenuEvent) = { def handleContextMenu(event: ContextMenuEvent) = {
//Build and show a context menu //Build and show a context menu
@ -46,38 +48,28 @@ class ImageTilePane extends TilePane with Logging {
def getSingleSelectionContextMenu : ContextMenu = { def getSingleSelectionContextMenu : ContextMenu = {
debug("Building single-selection context menu") debug("Building single-selection context menu")
val contextMenu = new ContextMenu() val contextMenu = new ContextMenu()
val item1 = new MenuItem("Single Selection")
item1.setOnAction(new EventHandler[ActionEvent]() {
val delete = new MenuItem("Delete")
delete.setOnAction(new EventHandler[ActionEvent]() {
def handle(e: ActionEvent) = { def handle(e: ActionEvent) = {
debug("Single Selection")
debug("Requesting Single Delete")
deleteSelected()
} }
}) })
val item2 = new MenuItem("BlahBlah")
item2.setOnAction(new EventHandler[ActionEvent]() {
def handle(e: ActionEvent) = {
debug("BlahBlah")
}
})
contextMenu.getItems.addAll(item1, item2)
contextMenu.getItems.addAll(delete)
contextMenu contextMenu
} }
def getMulipleSelectionContextMenu : ContextMenu = { def getMulipleSelectionContextMenu : ContextMenu = {
debug("Building multi-selection context menu") debug("Building multi-selection context menu")
val contextMenu = new ContextMenu() val contextMenu = new ContextMenu()
val item1 = new MenuItem("Multi Selection")
item1.setOnAction(new EventHandler[ActionEvent]() {
def handle(e: ActionEvent) = {
debug("Multi Selection")
}
})
val item2 = new MenuItem("BlahBlah")
item2.setOnAction(new EventHandler[ActionEvent]() {
val delete = new MenuItem("Delete")
delete.setOnAction(new EventHandler[ActionEvent]() {
def handle(e: ActionEvent) = { def handle(e: ActionEvent) = {
debug("BlahBlah")
debug("Requesting Multiple Delete")
deleteSelected()
} }
}) })
contextMenu.getItems.addAll(item1, item2)
contextMenu.getItems.addAll(delete)
contextMenu contextMenu
} }
@ -97,6 +89,33 @@ class ImageTilePane extends TilePane with Logging {
this.selectionModel.clearSelection() this.selectionModel.clearSelection()
} }
//request deletion of selected images
def deleteSelected() = {
val f: Future[Unit] = Future {
val selected = this.selectionModel.getSelectedItems
val iterator = selected.iterator()
while (iterator.hasNext) {
val item = iterator.next()
val imageTile = item.asInstanceOf[ImageTile]
val data = imageTile.imageData
val controller = AppConfig.getFxmlLoader.getController[AppController]()
controller.engine.deleteImage(data)
}
val pane = this
Platform.runLater(new Runnable() {
override def run(): Unit = {
//remove from the current panel
pane.getChildren.removeAll(selected)
clearSelection()
}
})
}
f onComplete {
case Success(a) => info("Successfully deleted files")
case Failure(f) => error("Failed to delete files", f)
}
}
} }
/** /**

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

@ -224,7 +224,7 @@ class AppController extends Logging {
tempImages += similarImage.rootImage tempImages += similarImage.rootImage
similarImage.similarImages.foreach(image => tempImages += image) similarImage.similarImages.foreach(image => tempImages += image)
} }
tempImages.toList.sortWith((x,y) => x.imagePath < y.imagePath)
tempImages.toList
} }
f onComplete { f onComplete {

Loading…
Cancel
Save