TextureSync/client/src/main/kotlin/org/hso/texturesyncclient/controller/RootController.kt

322 lines
11 KiB
Kotlin
Raw Normal View History

package org.hso.texturesyncclient.controller
2019-06-05 16:05:10 +02:00
import javafx.application.Platform
2019-06-03 17:33:23 +02:00
import javafx.collections.ObservableList
2019-06-06 14:41:30 +02:00
import javafx.event.EventHandler
import javafx.scene.image.Image
2019-06-04 18:20:09 +02:00
import javafx.stage.DirectoryChooser
2019-06-08 14:01:49 +02:00
import org.hso.texturesyncclient.alerts.JFXInfoAlert
2019-06-06 14:41:30 +02:00
import org.hso.texturesyncclient.alerts.JFXOkayCancelAlert
2019-06-07 09:52:09 +02:00
import org.hso.texturesyncclient.controller.net.AutoConnect
2019-06-03 16:46:57 +02:00
import org.hso.texturesyncclient.controller.net.Connection
2019-06-04 18:20:09 +02:00
import org.hso.texturesyncclient.model.GUIModel
2019-06-04 14:57:54 +02:00
import org.hso.texturesyncclient.model.Sha256
import org.hso.texturesyncclient.model.Texture
import org.hso.texturesyncclient.model.TextureFormat
2019-06-05 16:23:45 +02:00
import org.hso.texturesyncclient.view.importView.ImportView
2019-06-04 16:05:47 +02:00
import org.hso.texturesyncclient.view.mainView.MainView
import org.hso.texturesyncclient.view.mainView.MainViewController
2019-06-04 16:05:47 +02:00
import org.hso.texturesyncclient.view.startupView.StartupView
2019-06-03 16:46:57 +02:00
import org.hso.texturesyncclient.view.startupView.StartupViewController
import tornadofx.*
2019-06-03 21:40:02 +02:00
import java.io.File
import java.io.FileOutputStream
2019-06-08 14:01:49 +02:00
import java.io.IOException
2019-06-12 18:57:42 +02:00
import java.net.InetAddress
import java.nio.file.Files
2019-06-08 13:31:29 +02:00
import java.text.SimpleDateFormat
2019-06-12 18:57:42 +02:00
import java.util.*
import javax.imageio.ImageIO
2019-06-08 13:31:29 +02:00
2019-06-03 17:33:23 +02:00
class RootController : Controller() {
private val mvc: MainViewController by inject()
2019-06-03 16:46:57 +02:00
private val svc: StartupViewController by inject()
2019-06-04 16:05:47 +02:00
private lateinit var con: Connection
private lateinit var selectedTextureModel: GUIModel
private var lastExportDir: String = System.getProperty("user.home")
2019-06-05 16:05:10 +02:00
2019-06-03 17:33:23 +02:00
/**
* calculate the resolution, get today's date -> upload to server
* @param path the absolute path of the file on the client's system
* @param name the file name
* @param tags all tags for the file
*/
fun importTexture(path: String, name: String, tags: ObservableList<String>) {
2019-06-09 13:29:07 +02:00
val data = Files.readAllBytes(File(path).toPath()) // this is the image as byte array
2019-06-03 17:33:23 +02:00
2019-06-04 14:57:54 +02:00
val uuid = UUID.randomUUID()
val format = if (File(path).extension.toLowerCase() == "png") TextureFormat.PNG else TextureFormat.JPEG
val bimg = ImageIO.read(File(path)) //image for obtaining resolution
val resolution = Pair(bimg.width, bimg.height)
2019-06-04 14:57:54 +02:00
val cal = Calendar.getInstance() //calendar obj with current time
2019-06-05 16:05:10 +02:00
val hash = Sha256(data)
2019-06-04 14:57:54 +02:00
2019-06-08 14:20:48 +02:00
val alertImportHash = JFXInfoAlert(
"Upload fehlgeschlagen",
"Die Textur wurde nicht fehlerfrei übertragen",
"-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;"
)
val alertImport = JFXInfoAlert(
"Upload fehlgeschlagen",
"Mögliche Ursachen:" +
"\n- Textur existiert bereits" +
"\n- Server nicht bereit",
"-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;"
)
2019-06-03 20:42:28 +02:00
2019-06-04 14:57:54 +02:00
val newTexture = Texture(uuid, name, tags.toTypedArray(), format, resolution, cal, hash)
2019-06-03 20:42:28 +02:00
2019-06-04 16:05:47 +02:00
try {
con.uploadTexture(newTexture, data)
println("Texture upload successful")
2019-06-08 14:20:48 +02:00
} catch (e: IllegalArgumentException) {
2019-06-04 16:05:47 +02:00
println(e)
2019-06-08 14:20:48 +02:00
alertImportHash.showAndWait()
} catch (e: Exception) {
alertImport.showAndWait()
2019-06-09 13:29:07 +02:00
println(e)
2019-06-04 16:05:47 +02:00
}
2019-06-09 13:29:07 +02:00
2019-06-04 16:05:47 +02:00
}
/**
2019-06-05 16:05:10 +02:00
* Initialize connection to server and switch to MainView if connected
2019-06-04 16:05:47 +02:00
* @param name server name as IP or domain
*/
fun initConnection(name: String) {
2019-06-07 09:52:09 +02:00
if (name == " ") {
//no user input, try automatic connect or restore address from settings file
println("try auto connect")
try {
val foundServer = AutoConnect.searchServer()
if (foundServer != null) {
println("[auto] server found")
con = foundServer
con.ping()
println("[auto] Connection to Server successful")
2019-06-07 09:52:09 +02:00
switchStartupToMain()
2019-06-08 21:59:09 +02:00
showAll()
return // abort
2019-06-07 09:52:09 +02:00
} else {
println("[auto] no server found")
}
} catch (e: Exception) {
println(e)
println("[auto] Connection to Server NOT successful")
2019-06-07 09:52:09 +02:00
}
if (SettingsController.serverAddressIsSet()) {
println("[file] try connect with settings file")
try {
svc.setServerAddress(SettingsController.getServerAddress()) // FIXME this crashes the client when there is either not text or no label!
2019-06-07 09:52:09 +02:00
con = Connection(InetAddress.getByName(SettingsController.getServerAddress()))
con.ping()
println("[file] Connection to Server successful")
switchStartupToMain()
2019-06-08 21:59:09 +02:00
showAll()
return // abort
2019-06-07 09:52:09 +02:00
} catch (e: Exception) {
println(e)
println("[file] Connection to Server NOT successful")
}
} else {
2019-06-07 09:52:09 +02:00
println("[file] no address in settings file")
}
} else {
//try to connect with user input
try {
println("try connect with user input")
con = Connection(InetAddress.getByName(name))
con.ping()
println("Connection to Server successful")
SettingsController.setServerAddress(name) //store address in settings file
switchStartupToMain()
2019-06-08 21:59:09 +02:00
showAll()
2019-06-07 09:52:09 +02:00
println("swithing to MainView @ initCon")
return // abort
2019-06-07 09:52:09 +02:00
} catch (e: Exception) {
println(e)
println("Connection to Server NOT successful")
Platform.runLater {
JFXInfoAlert(
"Verbinden fehlgeschlagen",
"Mögliche Ursachen:" +
"\n- der angegebene Server ist offline" +
"\n- die benötigten Ports sind nicht offen",
"-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;"
).showAndWait()
}
2019-06-07 09:52:09 +02:00
}
2019-06-04 18:20:09 +02:00
}
}
2019-06-04 16:05:47 +02:00
fun queryElements(tags: ObservableList<String>): ArrayList<GUIModel> {
mvc.setVisibleMetaTags(false)
2019-06-04 18:20:09 +02:00
val previewList = arrayListOf<GUIModel>()
2019-06-04 16:05:47 +02:00
2019-06-04 18:20:09 +02:00
try {
con.query(tags.toTypedArray()).forEach {
runAsync {
Platform.runLater {
mvc.addElement(GUIModel(it, con.getTexturePreview(it.textureHash)))
}
}
2019-06-04 18:20:09 +02:00
}
2019-06-04 16:05:47 +02:00
} catch (e: Exception) {
println(e)
}
2019-06-04 18:20:09 +02:00
println(previewList.size)
return previewList
2019-06-03 17:33:23 +02:00
}
2019-06-03 22:24:18 +02:00
/**
* save the texture file to a local directory
* @param data the texture as meta element
*/
2019-06-04 18:20:09 +02:00
fun exportTexture(data: Texture) {
val directoryChooser = DirectoryChooser()
directoryChooser.title = "Export Verzeichnis wählen"
directoryChooser.initialDirectory = if(File(lastExportDir).exists()) File(lastExportDir) else File(System.getProperty("user.home"))
2019-06-04 18:20:09 +02:00
2019-06-08 14:01:49 +02:00
val alertExport = JFXInfoAlert(
"Exporterien fehlgeschlagen",
"Mögliche Ursachen:" +
2019-06-08 14:20:48 +02:00
"\n- Datei existiert bereits" +
"\n- Ordner nicht beschreibbar",
2019-06-08 14:01:49 +02:00
"-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;"
)
2019-06-04 18:20:09 +02:00
val dir = directoryChooser.showDialog(primaryStage)
if (dir != null) {
val extension = if (data.format == TextureFormat.PNG) ".png" else ".jpeg" //get file format
val filePath = "$dir/${data.name}$extension" //build absolute exported texture path
val exportedFile = File(filePath) //create file
2019-06-08 14:01:49 +02:00
if (exportedFile.exists()) {
alertExport.showAndWait()
} else {
try {
val fileout = FileOutputStream(exportedFile)
fileout.write(con.getTextureFile(data.textureHash)) //write bytes in file fileout.close()
fileout.close()
} catch (e: IOException) {
alertExport.showAndWait()
}
}
lastExportDir = dir.absolutePath //store last user chosen dir
2019-06-04 18:20:09 +02:00
}
}
/**
* show the detailed meta information in the DetailView
* @param data the texture as meta element
*/
2019-06-04 18:20:09 +02:00
fun showDetail(data: Texture) {
mvc.setPreview3DTexture(con.getTexturePreview(data.textureHash))
2019-06-08 13:31:29 +02:00
val sdf = SimpleDateFormat("dd.MM.yyyy")
2019-06-08 21:59:09 +02:00
mvc.setMeta(
data.name,
"${data.resolution.first}px x ${data.resolution.second}px",
data.format.toString(),
sdf.format(data.addedOn.time)
)
2019-06-04 18:20:09 +02:00
mvc.setTags(data.tags.toList().observable())
mvc.setVisibleMetaTags(true)
2019-06-04 18:20:09 +02:00
}
/**
* remove a texture from the FolderView and the server
*/
fun deleteTexture() {
2019-06-06 14:41:30 +02:00
val dialogDelete = JFXOkayCancelAlert(
"Löschen",
"Textur ${selectedTextureModel.data.name} wirklich löschen?",
2019-06-06 14:41:30 +02:00
"-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;"
)
dialogDelete.okayAction = EventHandler {
con.deleteTexture(selectedTextureModel.data)
mvc.removeTextureFromView(selectedTextureModel.data)
// reset the DetailView
mvc.setVisibleMetaTags(false)
mvc.setPreview3DTexture(Image("icons/TextureSync_Icon_256x256.jpeg"))
2019-06-06 14:41:30 +02:00
}
dialogDelete.cancelAction = EventHandler {
// Do nothing
2019-06-06 14:41:30 +02:00
}
dialogDelete.showAndWait()
}
fun updateTexture(name: String, tags: Array<String>) {
val newTexture = selectedTextureModel.data.copy(
tags = tags,
name = name
)
try {
2019-06-12 18:57:42 +02:00
con.updateTexture(
selectedTextureModel.data,
newTexture,
con.getTextureFile(selectedTextureModel.data.textureHash)
)
selectedTextureModel.data = newTexture
} catch (e: Exception) {
println(e)
}
}
2019-06-08 21:59:09 +02:00
/**
* show all available textures at start
*/
2019-06-09 13:38:11 +02:00
private fun showAll() {
2019-06-08 21:59:09 +02:00
queryElements(mvc.getTags())
}
2019-06-09 13:38:11 +02:00
/**
* set the last selected texture-GUIModell
* @param model the last selected element
*/
2019-06-12 18:57:42 +02:00
fun setSelectedTexture(model: GUIModel) {
selectedTextureModel = model
selectedTexture = model.data
}
2019-06-09 13:38:11 +02:00
companion object {
var selectedTexture: Texture? = null
2019-06-09 13:38:11 +02:00
fun switchStartupToMain() {
Platform.runLater {
find(StartupView::class).replaceWith(MainView::class, ViewTransition.FadeThrough(0.01.seconds))
2019-06-09 13:38:11 +02:00
}
}
// These runLater calls should be unnecessary
fun switchMainToImport() {
Platform.runLater {
find(MainView::class).replaceWith(ImportView::class, ViewTransition.FadeThrough(0.01.seconds))
2019-06-09 13:38:11 +02:00
}
}
fun switchImportToMain(needsReload: Boolean) {
2019-06-09 13:38:11 +02:00
Platform.runLater {
find(ImportView::class).replaceWith(MainView::class, ViewTransition.FadeThrough(0.01.seconds))
if (needsReload) {
find(MainView::class).repeatSearch()
}
2019-06-09 13:38:11 +02:00
}
}
}
}