package org.hso.texturesyncclient.controller import javafx.application.Platform import javafx.collections.ObservableList import javafx.event.EventHandler import javafx.scene.image.Image import javafx.stage.DirectoryChooser import org.hso.texturesyncclient.alerts.JFXInfoAlert import org.hso.texturesyncclient.alerts.JFXOkayCancelAlert import org.hso.texturesyncclient.controller.net.AutoConnect import org.hso.texturesyncclient.controller.net.Connection import org.hso.texturesyncclient.model.GUIModel import org.hso.texturesyncclient.model.Sha256 import org.hso.texturesyncclient.model.Texture import org.hso.texturesyncclient.model.TextureFormat import org.hso.texturesyncclient.view.importView.ImportView import org.hso.texturesyncclient.view.mainView.MainView import org.hso.texturesyncclient.view.mainView.MainViewController import org.hso.texturesyncclient.view.startupView.StartupView import org.hso.texturesyncclient.view.startupView.StartupViewController import tornadofx.* import java.io.File import java.io.FileOutputStream import java.io.IOException import java.net.InetAddress import java.nio.file.Files import java.text.SimpleDateFormat import java.util.* import javax.imageio.ImageIO class RootController : Controller() { private val mvc: MainViewController by inject() private val svc: StartupViewController by inject() private lateinit var con: Connection private lateinit var selectedTextureModel: GUIModel private var lastExportDir: String = System.getProperty("user.home") /** * 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) { val data = Files.readAllBytes(File(path).toPath()) // this is the image as byte array 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) val cal = Calendar.getInstance() //calendar obj with current time val hash = Sha256(data) 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;" ) val newTexture = Texture(uuid, name, tags.toTypedArray(), format, resolution, cal, hash) try { con.uploadTexture(newTexture, data) println("Texture upload successful") } catch (e: IllegalArgumentException) { println(e) alertImportHash.showAndWait() } catch (e: Exception) { alertImport.showAndWait() println(e) } } /** * Initialize connection to server and switch to MainView if connected * @param name server name as IP or domain */ fun initConnection(name: String) { 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") switchStartupToMain() showAll() return // abort } else { println("[auto] no server found") } } catch (e: Exception) { println(e) println("[auto] Connection to Server NOT successful") } 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! con = Connection(InetAddress.getByName(SettingsController.getServerAddress())) con.ping() println("[file] Connection to Server successful") switchStartupToMain() showAll() return // abort } catch (e: Exception) { println(e) println("[file] Connection to Server NOT successful") } } else { 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() showAll() println("swithing to MainView @ initCon") return // abort } 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() } } } } fun queryElements(tags: ObservableList): ArrayList { mvc.setVisibleMetaTags(false) val previewList = arrayListOf() try { con.query(tags.toTypedArray()).forEach { runAsync { Platform.runLater { mvc.addElement(GUIModel(it, con.getTexturePreview(it.textureHash))) } } } } catch (e: Exception) { println(e) } println(previewList.size) return previewList } /** * save the texture file to a local directory * @param data the texture as meta element */ 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")) val alertExport = JFXInfoAlert( "Exporterien fehlgeschlagen", "Mögliche Ursachen:" + "\n- Datei existiert bereits" + "\n- Ordner nicht beschreibbar", "-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;" ) 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 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 } } /** * show the detailed meta information in the DetailView * @param data the texture as meta element */ fun showDetail(data: Texture) { mvc.setPreview3DTexture(con.getTexturePreview(data.textureHash)) val sdf = SimpleDateFormat("dd.MM.yyyy") mvc.setMeta( data.name, "${data.resolution.first}px x ${data.resolution.second}px", data.format.toString(), sdf.format(data.addedOn.time) ) mvc.setTags(data.tags.toList().observable()) mvc.setVisibleMetaTags(true) } /** * remove a texture from the FolderView and the server */ fun deleteTexture() { val dialogDelete = JFXOkayCancelAlert( "Löschen", "Textur ${selectedTextureModel.data.name} wirklich löschen?", "-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")) } dialogDelete.cancelAction = EventHandler { // Do nothing } dialogDelete.showAndWait() } fun updateTexture(name: String, tags: Array) { val newTexture = selectedTextureModel.data.copy( tags = tags, name = name ) try { con.updateTexture( selectedTextureModel.data, newTexture, con.getTextureFile(selectedTextureModel.data.textureHash) ) selectedTextureModel.data = newTexture } catch (e: Exception) { println(e) } } /** * show all available textures at start */ private fun showAll() { queryElements(mvc.getTags()) } /** * set the last selected texture-GUIModell * @param model the last selected element */ fun setSelectedTexture(model: GUIModel) { selectedTextureModel = model selectedTexture = model.data } companion object { var selectedTexture: Texture? = null fun switchStartupToMain() { Platform.runLater { find(StartupView::class).replaceWith(MainView::class, ViewTransition.FadeThrough(0.01.seconds)) } } // These runLater calls should be unnecessary fun switchMainToImport() { Platform.runLater { find(MainView::class).replaceWith(ImportView::class, ViewTransition.FadeThrough(0.01.seconds)) } } fun switchImportToMain(needsReload: Boolean) { Platform.runLater { find(ImportView::class).replaceWith(MainView::class, ViewTransition.FadeThrough(0.01.seconds)) if (needsReload) { find(MainView::class).repeatSearch() } } } } }