117 Commits

Author SHA1 Message Date
ad00b2ca56 spelling fixes in praesentation 2019-06-20 11:54:07 +02:00
53e90b7c32 completed praesentation 2019-06-20 10:35:13 +02:00
d3e4ee71c9 fix windows not auto reconnecting 2019-06-19 21:33:21 +02:00
e95248ec5e change default timeout 2019-06-19 15:49:13 +02:00
71b735785f increment Server Version to 1.0.2 2019-06-19 15:47:23 +02:00
57029b42ff updated client version to 1.0.2 2019-06-19 15:14:21 +02:00
d9aed568b7 added Tech-Client to praesentation 2019-06-19 15:05:34 +02:00
f444fd2d6e Added client tech to presentation 2019-06-19 14:31:56 +02:00
a59cc07e83 added Traceability 2019-06-19 14:04:00 +02:00
8ff6011aeb added tech server slide 2019-06-18 23:01:53 +02:00
5351986d65 Add information about Rust to presentation 2019-06-18 17:02:52 +02:00
1526c7f4bd praesentation 2019-06-18 16:31:00 +02:00
798fde14be praesentationo 2019-06-18 16:24:28 +02:00
57eaf0d927 praesentation 2019-06-18 15:58:20 +02:00
a05660d036 praesentation 2019-06-18 15:02:17 +02:00
1e029e7940 increase import btn text size 2019-06-17 23:00:19 +02:00
3cf401f3a1 don't use semicolon in kotlin 2019-06-17 22:40:52 +02:00
f026a0dcf7 Reload search results after adding a new texture
Closes #54
2019-06-17 20:19:54 +02:00
74565e5744 fixed layout in akzeptanztest-v1.0.1 2019-06-17 18:04:52 +02:00
01442b313f fixed grobdesign and charter 2019-06-14 18:28:12 +02:00
d38b195d92 updated statusbericht kw#24 2019-06-14 18:09:31 +02:00
6cf6d21e95 Do module tests on version 1.0.1
Closes #49
2019-06-14 17:53:47 +02:00
d59bd67d14 Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-14 16:00:36 +02:00
decc46cc2d add autoconnect to grobdesign 2019-06-14 16:00:11 +02:00
6bb21235c5 systemtest-v1.0.1 2019-06-14 15:32:25 +02:00
f2a3ffae9e spelling fixes in statusbericht kw#24 2019-06-14 15:21:58 +02:00
5f4a7fe7e6 Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-14 15:07:51 +02:00
b4a1116513 added akzeptanztest for release 1.0.1 2019-06-14 15:07:23 +02:00
e742f39f51 do integrationstest-v1.0.1
Resolves #51
2019-06-14 15:02:49 +02:00
62700850b1 duplicate all test docs & add version to filename 2019-06-14 14:54:35 +02:00
fb9e712778 updated test docs 2019-06-14 14:47:16 +02:00
b8ca5dc498 added ST#24 2019-06-14 14:23:18 +02:00
dbdba120c3 tested Akzeptanztests 2019-06-14 14:20:59 +02:00
33a46c4cbf added sync systemtests 2019-06-14 12:35:45 +02:00
d81aa56e49 Server Version in Cargo.toml -> '1.0.1' 2019-06-14 12:27:38 +02:00
95496536db Worarround for #43 #44
Use 'invisible' ViewTransition (0.01 seconds)
Fixes #43
Fixes #44
2019-06-14 12:19:55 +02:00
8f3b61462a remove TODO in Systemtests 2019-06-14 12:09:19 +02:00
cff5ec76bf Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-14 12:07:58 +02:00
1bbfe800e1 fix '1.0.0-beta' -> '1.0.0'
'1.0.0-beta' does not exist.
2019-06-14 12:06:37 +02:00
c722a39116 first set of systemtests 2019-06-14 11:52:00 +02:00
911983bff4 don't crash if the previously selected export directory doesn't exist 2019-06-14 11:38:20 +02:00
6feb1c3dad Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-14 11:29:35 +02:00
7da58c7dbe Fix #42, dont load IP from File, if auto-connected 2019-06-14 11:28:43 +02:00
86c05c0363 show width x height, not the other way round 2019-06-14 11:18:58 +02:00
a3c03c4bc7 Make search for texture name case-insensitive
Fixes #47
2019-06-14 11:12:56 +02:00
9444e8198f Repeat Test MT#10 in module tests 2019-06-14 10:37:14 +02:00
730a0ab383 Fix "fix #46" 2019-06-14 01:14:01 +02:00
a10e2aceb6 Revert "fix #46"
This reverts commit f0fe4bb981.
2019-06-14 01:12:33 +02:00
f0fe4bb981 fix #46 2019-06-14 01:09:30 +02:00
32883a2639 Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-14 01:01:23 +02:00
0e293768d7 integrationstest ausfüllen 2019-06-14 01:00:52 +02:00
6a5b2f555c Do the module tests 2019-06-14 00:48:48 +02:00
8d210d756d Integrationstest: Ergebnisbeschreibung präzisiert. 2019-06-14 00:36:04 +02:00
8c6a43fc22 change version to 1.0 2019-06-13 22:21:41 +02:00
7f4182bfad added JFXInfoAlert if connect manually failed
closes #39
2019-06-13 21:52:26 +02:00
5fff4023f9 clear DetailVIew on delete, rename submitButton to btnSubmit, clean up 2019-06-13 21:43:43 +02:00
dfad679e6e updated planner 2019-06-13 21:36:14 +02:00
391dfe4282 don't open export if nothing is selected & clean up 2019-06-13 21:22:42 +02:00
225316abb9 Merge branch 'fix-40' of localhorst/TextureSync into master 2019-06-13 20:04:44 +02:00
f5dbcc0134 use Borderpane + Anchorpane for #40 2019-06-13 18:38:38 +02:00
cac4807357 BUG FIX: show resolution in detailview. 2019-06-13 18:37:07 +02:00
33fa741a2a fix font-color of import action btn 2019-06-13 18:35:34 +02:00
37406acd98 Fix #27 (StartupViewController is created twice) again 2019-06-13 18:04:46 +02:00
56c62422cc use blue for "Ändern" Button 2019-06-13 00:19:16 +02:00
bc43b33536 Fix #38
Note: The client architecture is broken beyond repair
2019-06-13 00:10:00 +02:00
1ac13f80d5 fix MainView ChipView TextColor 2019-06-12 22:54:30 +02:00
8dfbbae559 fix #28 2019-06-12 22:42:28 +02:00
cc03b32ade Fix #29
Redo Text of FolderView + DetailView
2019-06-12 21:05:40 +02:00
a2f5b65e30 Calling App.start(stage) early
Calling super.start early prevents a weird layouting bug
were the button of the window is white.
This could(?) be caused by stage and StartupView having
a different min-size.
2019-06-12 19:37:32 +02:00
f094a68b04 Merge branch 'resize' 2019-06-12 19:11:08 +02:00
b5545e1bae fix icon path: use png for alpha-channel 2019-06-12 19:07:29 +02:00
9a9a1e0056 Merge commit '10076fc' into resize 2019-06-12 19:03:26 +02:00
0f23749001 Merge commit '6219ad9' into resize 2019-06-12 19:03:19 +02:00
c1dbd8ffb7 Merge commit '35f8145' into resize 2019-06-12 19:03:05 +02:00
ebc6449e48 Merge commit 'e26d54e' into resize 2019-06-12 19:02:50 +02:00
bef56f978c Merge commit '9975364' into resize 2019-06-12 19:02:12 +02:00
50ea54c8d6 reformat 2019-06-12 18:57:42 +02:00
24b9755089 Merge commit '4915788' into resize 2019-06-12 18:56:37 +02:00
6fbfa050b3 Merge commit 'ee7fbae' into resize 2019-06-12 18:53:57 +02:00
9a3524143a Merge commit 'efc2845' into resize 2019-06-12 18:53:42 +02:00
10076fcef2 updated test docs 2019-06-12 14:08:23 +02:00
6219ad93d0 Fix #31 : Config Path use ~/.config instead.
This is more common for Desktop Apps.
2019-06-12 13:28:03 +02:00
8109782e4e Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-12 13:24:26 +02:00
c2d01760c7 Set Server Version to 1.0; Show Version on Startup 2019-06-12 13:23:47 +02:00
2cac52b48d Replace logo with the new one 2019-06-12 11:38:05 +02:00
35f8145112 [kurzanleitung] added first thoughts 2019-06-10 16:05:07 +02:00
e26d54e96f added praesentation 2019-06-10 15:58:32 +02:00
7e3ce9ce56 fixed StartupViewController is created twice
closes #27
2019-06-10 15:30:00 +02:00
9975364621 updated all test documents 2019-06-10 15:19:53 +02:00
491578806e Multiple changes in the ChipView will now work for the update to server 2019-06-10 14:05:56 +02:00
b1052fa894 added shortcut ctrl+e for exporting a texture 2019-06-10 12:41:11 +02:00
36c4805061 added shortcut ctrl+i for the ImportView 2019-06-10 12:25:06 +02:00
ee7fbae29c Fix display of the month at creation date
This time on serialization as well as on deserialization
2019-06-09 16:29:37 +02:00
07f2682a2d resize ImportView too 2019-06-09 13:38:11 +02:00
efc28455c1 fixed error handling at import 2019-06-09 13:29:07 +02:00
5d223ba72b make window resizable, rework MainView code 2019-06-09 13:12:56 +02:00
15cbbb1bac fast fix for calendar bug 2019-06-09 13:03:20 +02:00
08840c4c2b Revert "Fix display of the month at creation date"
This reverts commit 19eb6660e1.
2019-06-09 13:02:26 +02:00
6b6ef67122 Revert "Make Client resizeable"
This reverts commit 36a8bccfe3.
2019-06-08 22:46:34 +02:00
4a213afdf5 Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-08 22:17:24 +02:00
36a8bccfe3 Make Client resizeable 2019-06-08 22:16:47 +02:00
4f35293151 hide metadata and ChipView in DetailView 2019-06-08 22:09:43 +02:00
29354199cc show all textures at startup 2019-06-08 21:59:09 +02:00
f4db466b37 Client Connection: [Auto]Retry Once
if Connection is lost or timed out
2019-06-08 21:25:56 +02:00
19eb6660e1 Fix display of the month at creation date 2019-06-08 16:35:45 +02:00
4e8b4c364b Add java program to create test data 2019-06-08 16:07:55 +02:00
f22a9eb260 added com.github.johnrengelman.shadow
this makes it a lot easier to build a runnable jar file
2019-06-08 15:32:05 +02:00
9ae50df1a4 don't resize the window, set the correct Title
* closes #19
2019-06-08 14:39:18 +02:00
ce11d2e263 added a icon 2019-06-08 14:27:11 +02:00
3f18760a74 Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-08 14:21:34 +02:00
89ef736954 alert if import failed 2019-06-08 14:20:48 +02:00
3e1c46db81 some clean up, adjusted the DetailView background 2019-06-08 14:19:14 +02:00
be11f35159 show alert if export fails 2019-06-08 14:01:49 +02:00
39c358c00f update to JFoenix 8.0.9
* added a promptText to the search ChipView
2019-06-08 13:48:16 +02:00
61980905e3 changed debbuging color in 3DPreview to release color 2019-06-08 13:40:59 +02:00
fc5db5d051 Merge branch 'master' of git.mosad.xyz:localhorst/TextureSync 2019-06-08 13:32:09 +02:00
4c2e1c2917 show metadata in better format 2019-06-08 13:31:29 +02:00
80 changed files with 497215 additions and 100928 deletions

View File

@ -15,10 +15,21 @@ buildscript {
plugins { plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.31' id 'org.jetbrains.kotlin.jvm' version '1.3.31'
id "com.github.johnrengelman.shadow" version "5.0.0"
id "application"
} }
group 'com.hso' compileKotlin {
version '1.0-SNAPSHOT' kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
group 'org.hso'
version '1.0.2'
archivesBaseName = 'TextureSync'
mainClassName = 'org.hso.texturesyncclient.app.Main'
repositories { repositories {
mavenCentral() mavenCentral()
@ -27,13 +38,6 @@ repositories {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "no.tornado:tornadofx:$tornadofx_version" implementation "no.tornado:tornadofx:$tornadofx_version"
implementation "com.jfoenix:jfoenix:8.0.8" implementation "com.jfoenix:jfoenix:8.0.9"
implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.code.gson:gson:2.8.5'
} }
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}

View File

@ -1,2 +1,2 @@
rootProject.name = 'texuresync_client' rootProject.name = 'texturesync_client'

View File

@ -1,19 +1,36 @@
package org.hso.texturesyncclient.app package org.hso.texturesyncclient.app
import javafx.scene.image.Image
import javafx.stage.Stage import javafx.stage.Stage
import org.hso.texturesyncclient.controller.SettingsController
import org.hso.texturesyncclient.view.startupView.StartupView import org.hso.texturesyncclient.view.startupView.StartupView
import org.hso.texturesyncclient.view.startupView.StartupViewController import org.hso.texturesyncclient.view.startupView.StartupViewController
import tornadofx.App import tornadofx.App
class Main: App(StartupView::class){ class Main : App(StartupView::class) {
//start first controller private val svc: StartupViewController by inject()
private val svc = StartupViewController()
override fun start(stage: Stage) { override fun start(stage: Stage) {
// Calling super.start early prevents a weird layouting bug
// were the button of the window is white.
// This could(?) be caused by stage and StartupView having
// a different min-size.
super.start(stage) super.start(stage)
stage.minWidth = 1050.00
stage.minHeight = 700.00
stage.width = 1050.00
stage.height = 700.00
stage.isResizable = true
stage.icons.add(Image("icons/TextureSync_Icon_256x256.png"))
stage.setOnCloseRequest { System.exit(0) } stage.setOnCloseRequest { System.exit(0) }
stage.scene.stylesheets.add("/css/Styles.css") stage.scene.stylesheets.add("/css/Styles.css")
SettingsController.init()
svc.initConnection()
} }
} }

View File

@ -3,7 +3,9 @@ package org.hso.texturesyncclient.controller
import javafx.application.Platform import javafx.application.Platform
import javafx.collections.ObservableList import javafx.collections.ObservableList
import javafx.event.EventHandler import javafx.event.EventHandler
import javafx.scene.image.Image
import javafx.stage.DirectoryChooser import javafx.stage.DirectoryChooser
import org.hso.texturesyncclient.alerts.JFXInfoAlert
import org.hso.texturesyncclient.alerts.JFXOkayCancelAlert import org.hso.texturesyncclient.alerts.JFXOkayCancelAlert
import org.hso.texturesyncclient.controller.net.AutoConnect import org.hso.texturesyncclient.controller.net.AutoConnect
import org.hso.texturesyncclient.controller.net.Connection import org.hso.texturesyncclient.controller.net.Connection
@ -12,31 +14,27 @@ import org.hso.texturesyncclient.model.Sha256
import org.hso.texturesyncclient.model.Texture import org.hso.texturesyncclient.model.Texture
import org.hso.texturesyncclient.model.TextureFormat import org.hso.texturesyncclient.model.TextureFormat
import org.hso.texturesyncclient.view.importView.ImportView import org.hso.texturesyncclient.view.importView.ImportView
import org.hso.texturesyncclient.view.importView.ImportViewController
import org.hso.texturesyncclient.view.mainView.MainView import org.hso.texturesyncclient.view.mainView.MainView
import org.hso.texturesyncclient.view.mainView.MainViewController import org.hso.texturesyncclient.view.mainView.MainViewController
import org.hso.texturesyncclient.view.startupView.StartupView import org.hso.texturesyncclient.view.startupView.StartupView
import org.hso.texturesyncclient.view.startupView.StartupViewController import org.hso.texturesyncclient.view.startupView.StartupViewController
import tornadofx.Controller import tornadofx.*
import tornadofx.observable
import java.net.InetAddress
import java.util.Calendar
import java.io.File import java.io.File
import javax.imageio.ImageIO
import java.util.UUID
import java.nio.file.Files
import java.io.FileOutputStream 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() { class RootController : Controller() {
private val mvc: MainViewController by inject() private val mvc: MainViewController by inject()
private val svc: StartupViewController by inject() private val svc: StartupViewController by inject()
private val ivc: ImportViewController by inject()
private lateinit var con: Connection private lateinit var con: Connection
private lateinit var selectedTextureModel: GUIModel
private lateinit var selectedTexture: Texture
private var lastExportDir: String = System.getProperty("user.home") private var lastExportDir: String = System.getProperty("user.home")
/** /**
@ -51,20 +49,39 @@ class RootController : Controller() {
val uuid = UUID.randomUUID() val uuid = UUID.randomUUID()
val format = if (File(path).extension.toLowerCase() == "png") TextureFormat.PNG else TextureFormat.JPEG val format = if (File(path).extension.toLowerCase() == "png") TextureFormat.PNG else TextureFormat.JPEG
val bimg = ImageIO.read(File(path)) //image for obtaining resolution val bimg = ImageIO.read(File(path)) //image for obtaining resolution
val resolution = Pair(bimg.height, bimg.width) val resolution = Pair(bimg.width, bimg.height)
val cal = Calendar.getInstance() //calendar obj with current time val cal = Calendar.getInstance() //calendar obj with current time
val hash = Sha256(data) val hash = Sha256(data)
//Todo free image
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) val newTexture = Texture(uuid, name, tags.toTypedArray(), format, resolution, cal, hash)
try { try {
con.uploadTexture(newTexture, data) con.uploadTexture(newTexture, data)
println("Texture upload successful") println("Texture upload successful")
} catch (e: IllegalArgumentException) {
println(e)
alertImportHash.showAndWait()
} catch (e: Exception) { } catch (e: Exception) {
alertImport.showAndWait()
println(e) println(e)
} }
} }
/** /**
@ -81,14 +98,17 @@ class RootController : Controller() {
println("[auto] server found") println("[auto] server found")
con = foundServer con = foundServer
con.ping() con.ping()
println("auto Connection to Server successful") println("[auto] Connection to Server successful")
switchStartupToMain() switchStartupToMain()
showAll()
return // abort
} else { } else {
println("[auto] no server found") println("[auto] no server found")
} }
} catch (e: Exception) { } catch (e: Exception) {
println(e) println(e)
println("auto Connection to Server NOT successful") println("[auto] Connection to Server NOT successful")
} }
if (SettingsController.serverAddressIsSet()) { if (SettingsController.serverAddressIsSet()) {
println("[file] try connect with settings file") println("[file] try connect with settings file")
@ -98,6 +118,9 @@ class RootController : Controller() {
con.ping() con.ping()
println("[file] Connection to Server successful") println("[file] Connection to Server successful")
switchStartupToMain() switchStartupToMain()
showAll()
return // abort
} catch (e: Exception) { } catch (e: Exception) {
println(e) println(e)
println("[file] Connection to Server NOT successful") println("[file] Connection to Server NOT successful")
@ -114,15 +137,30 @@ class RootController : Controller() {
println("Connection to Server successful") println("Connection to Server successful")
SettingsController.setServerAddress(name) //store address in settings file SettingsController.setServerAddress(name) //store address in settings file
switchStartupToMain() switchStartupToMain()
showAll()
println("swithing to MainView @ initCon") println("swithing to MainView @ initCon")
return // abort
} catch (e: Exception) { } catch (e: Exception) {
println(e) println(e)
println("Connection to Server NOT successful") 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<String>): ArrayList<GUIModel> { fun queryElements(tags: ObservableList<String>): ArrayList<GUIModel> {
mvc.setVisibleMetaTags(false)
val previewList = arrayListOf<GUIModel>() val previewList = arrayListOf<GUIModel>()
try { try {
@ -142,26 +180,6 @@ class RootController : Controller() {
return previewList return previewList
} }
// TODO this could be a companion object
fun switchStartupToMain() {
Platform.runLater {
find(StartupView::class).replaceWith(MainView::class, sizeToScene = true, centerOnScreen = true)
}
}
// These runLater calls should be unnecessary
fun switchMainToImport() {
Platform.runLater {
find(MainView::class).replaceWith(ImportView::class, sizeToScene = true, centerOnScreen = true)
}
}
fun switchImportToMain() {
Platform.runLater {
find(ImportView::class).replaceWith(MainView::class, sizeToScene = true, centerOnScreen = true)
}
}
/** /**
* save the texture file to a local directory * save the texture file to a local directory
* @param data the texture as meta element * @param data the texture as meta element
@ -169,17 +187,34 @@ class RootController : Controller() {
fun exportTexture(data: Texture) { fun exportTexture(data: Texture) {
val directoryChooser = DirectoryChooser() val directoryChooser = DirectoryChooser()
directoryChooser.title = "Export Verzeichnis wählen" directoryChooser.title = "Export Verzeichnis wählen"
directoryChooser.initialDirectory = File(lastExportDir) 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) val dir = directoryChooser.showDialog(primaryStage)
if (dir != null) { if (dir != null) {
val extension = if (data.format == TextureFormat.PNG) ".png" else ".jpeg" //get file format 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 filePath = "$dir/${data.name}$extension" //build absolute exported texture path
val exportedFile = File(filePath) //create file val exportedFile = File(filePath) //create file
val fileout = FileOutputStream(exportedFile)
fileout.write(con.getTextureFile(data.textureHash)) //write bytes in file
fileout.close()
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 lastExportDir = dir.absolutePath //store last user chosen dir
} }
} }
@ -190,24 +225,33 @@ class RootController : Controller() {
*/ */
fun showDetail(data: Texture) { fun showDetail(data: Texture) {
mvc.setPreview3DTexture(con.getTexturePreview(data.textureHash)) mvc.setPreview3DTexture(con.getTexturePreview(data.textureHash))
mvc.setMeta(data.name, data.resolution.toString(), "") 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.setTags(data.tags.toList().observable())
selectedTexture = data mvc.setVisibleMetaTags(true)
} }
/** /**
* remove a texture from the FolderView and the server * remove a texture from the FolderView and the server
* @param data the texture as meta element
*/ */
fun deleteTexture(data: Texture) { fun deleteTexture() {
val dialogDelete = JFXOkayCancelAlert( val dialogDelete = JFXOkayCancelAlert(
"Löschen", "Löschen",
"Textur wirklich löschen?", "Textur ${selectedTextureModel.data.name} wirklich löschen?",
"-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;" "-fx-button-type: RAISED; -fx-background-color: #2b7bbb; -fx-text-fill: #000000;"
) )
dialogDelete.okayAction = EventHandler { dialogDelete.okayAction = EventHandler {
mvc.removeTextureFromView(data) con.deleteTexture(selectedTextureModel.data)
con.deleteTexture(data) mvc.removeTextureFromView(selectedTextureModel.data)
// reset the DetailView
mvc.setVisibleMetaTags(false)
mvc.setPreview3DTexture(Image("icons/TextureSync_Icon_256x256.jpeg"))
} }
dialogDelete.cancelAction = EventHandler { dialogDelete.cancelAction = EventHandler {
// Do nothing // Do nothing
@ -215,19 +259,64 @@ class RootController : Controller() {
dialogDelete.showAndWait() dialogDelete.showAndWait()
} }
fun updateTexture(name: String, tags: Array<String>) {
fun updateTexture(chips: ObservableList<String>) { val newTexture = selectedTextureModel.data.copy(
val uuid = UUID.randomUUID() tags = tags,
val newTexture = Texture( name = name
uuid,
selectedTexture.name,
chips.toTypedArray(),
selectedTexture.format,
selectedTexture.resolution,
selectedTexture.addedOn,
selectedTexture.textureHash
) )
con.updateTexture(selectedTexture, newTexture, con.getTextureFile(selectedTexture.textureHash)) 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()
}
}
}
}
} }

View File

@ -26,7 +26,7 @@ class SettingsController {
dirPath = if (osName.contains("Windows")) { dirPath = if (osName.contains("Windows")) {
"$userHome/Documents/TextureSync" "$userHome/Documents/TextureSync"
} else { } else {
"$userHome/.TextureSync" "$userHome/.config/TextureSync"
} }
settingsFile = File("$dirPath/config.xml") //open Settings file settingsFile = File("$dirPath/config.xml") //open Settings file

View File

@ -19,11 +19,11 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
@Throws(IOException::class) @Throws(IOException::class)
@Synchronized @Synchronized
private fun getStreams(): Pair<DataInputStream, DataOutputStream> { private fun <R> withStreams(retry: Boolean = true, inner: (DataInputStream, DataOutputStream) -> R): R {
val i: DataInputStream val i: DataInputStream
val o: DataOutputStream val o: DataOutputStream
if (socket == null || !socket!!.isConnected) { if (socket == null || socket!!.isClosed || !socket!!.isConnected) {
val sock = Socket() val sock = Socket()
sock.soTimeout = 10_000 /*ms*/ sock.soTimeout = 10_000 /*ms*/
sock.keepAlive = true sock.keepAlive = true
@ -40,242 +40,253 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
o = output!! o = output!!
} }
return Pair(i, o) return try {
inner(i, o)
} catch (e: IOException) {
if (retry) {
println("Got IOException; Retry ${e.message}")
close()
withStreams(false, inner)
} else {
throw e
}
}
} }
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun ping() { fun ping() {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("ping", JsonObject()) obj.add("ping", JsonObject())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> return is JsonPackage -> return@withStreams
is BinaryPackage -> throw ConnectionUnexpectedPacketException() is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg) is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable") else -> throw RuntimeException("Unreachable")
}
} }
} }
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun query(query: Array<String>): Array<Texture> { fun query(query: Array<String>): Array<Texture> {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject() val obj = JsonObject()
obj.add("query", { obj.add("query", {
val inner = JsonObject() val inner = JsonObject()
inner.add("query", { inner.add("query", {
val array = JsonArray() val array = JsonArray()
for (queryString in query) { for (queryString in query) {
array.add(queryString) array.add(queryString)
} }
array array
}())
inner
}()) }())
inner
}())
JsonPackage(obj).write(io.second) JsonPackage(obj).write(o)
when (val pkg = Package.read(io.first)) { when (val pkg = Package.read(i)) {
is JsonPackage -> { is JsonPackage -> {
try { try {
return Gson().fromJson<Array<InternalTexture>>(pkg.content, Array<InternalTexture>::class.java) return@withStreams Gson().fromJson<Array<InternalTexture>>(
.map { tex -> pkg.content,
tex.toTexture() Array<InternalTexture>::class.java
}.toTypedArray() )
} catch (e: JsonSyntaxException) { .map { tex ->
throw ConnectionInvalidJsonException() tex.toTexture()
}.toTypedArray()
} catch (e: JsonSyntaxException) {
throw ConnectionInvalidJsonException()
}
} }
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
} }
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
} }
} }
@Throws(IOException::class, ConnectionException::class) @Throws(IOException::class, ConnectionException::class)
@Synchronized
fun getTextureById(id: UUID): Texture? { fun getTextureById(id: UUID): Texture? {
val io = getStreams() return withStreams { i, o ->
val obj = JsonObject()
obj.add("get_texture", {
val inner = JsonObject()
inner.addProperty("id", id.toString())
inner
}())
JsonPackage(obj).write(io.second) val obj = JsonObject()
obj.add("get_texture", {
val inner = JsonObject()
inner.addProperty("id", id.toString())
inner
}())
when (val pkg = Package.read(io.first)) { JsonPackage(obj).write(o)
is JsonPackage -> {
return if (pkg.content.isJsonNull) {
null
} else {
try {
Gson()
.fromJson<InternalTexture>(pkg.content, InternalTexture::class.java)
.toTexture()
} catch (e: JsonSyntaxException) {
throw ConnectionInvalidJsonException()
}
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
} when (val pkg = Package.read(i)) {
is JsonPackage -> {
@Throws(IOException::class, ConnectionException::class) return@withStreams if (pkg.content.isJsonNull) {
@Synchronized null
fun getTextureByName(name: String): Texture? { } else {
val io = getStreams() try {
Gson()
val obj = JsonObject() .fromJson<InternalTexture>(pkg.content, InternalTexture::class.java)
obj.add("get_texture", { .toTexture()
val inner = JsonObject() } catch (e: JsonSyntaxException) {
inner.addProperty("name", name) throw ConnectionInvalidJsonException()
inner
}())
JsonPackage(obj).write(io.second)
when (val pkg = Package.read(io.first)) {
is JsonPackage -> {
return if (pkg.content.isJsonNull) {
null
} else {
try {
Gson()
.fromJson<InternalTexture>(pkg.content, InternalTexture::class.java)
.toTexture()
} catch (e: JsonSyntaxException) {
throw ConnectionInvalidJsonException()
}
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
@Throws(IOException::class, ConnectionException::class)
@Synchronized
fun getTextureFile(hash: Sha256): ByteArray {
val io = getStreams()
val obj = JsonObject()
obj.add("get_texture_file", {
val inner = JsonObject()
inner.addProperty("texture_hash", hash.toString())
inner
}())
JsonPackage(obj).write(io.second)
when (val pkg = Package.read(io.first)) {
is JsonPackage -> throw ConnectionUnexpectedPacketException()
is BinaryPackage -> return pkg.content
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
@Throws(IOException::class, ConnectionException::class)
@Synchronized
fun getTexturePreview(hash: Sha256): Image {
val io = getStreams()
val obj = JsonObject()
obj.add("get_texture_preview", {
val inner = JsonObject()
inner.addProperty("texture_hash", hash.toString())
inner.addProperty("desired_format", "jpeg")
inner
}())
JsonPackage(obj).write(io.second)
when (val pkg = Package.read(io.first)) {
is JsonPackage -> throw ConnectionUnexpectedPacketException()
is BinaryPackage -> {
return Image(ByteArrayInputStream(pkg.content))
}
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
private fun replaceTexture(old: Texture?, new: Texture?, image: ByteArray?) {
val io = getStreams()
val obj = JsonObject()
obj.add("replace_texture", {
val inner = JsonObject()
if (old != null) {
inner.add("old", Gson().toJsonTree(InternalTexture(old), InternalTexture::class.java))
} else {
inner.add("old", null)
}
if (new != null) {
inner.add("new", Gson().toJsonTree(InternalTexture(new), InternalTexture::class.java))
} else {
inner.add("new", null)
}
inner
}())
JsonPackage(obj).write(io.second)
when (val pkg = Package.read(io.first)) {
is JsonPackage -> {
when {
pkg.content == JsonPrimitive(true) -> // everthing is fine!
return
image != null -> {
// should be { "get_texture_file": { texture_hash : <Hash> }}
// we don't check, since there is no good way to handle it.
BinaryPackage(image).write(io.second)
when (val ipkg = Package.read(io.first)) {
is JsonPackage -> {
if (ipkg.content != JsonPrimitive(true)) {
// Protokoll Assertion failed
throw ConnectionUnexpectedPacketException()
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(ipkg)
else -> throw RuntimeException("Unreachable")
} }
} }
else -> { }
ErrorPackage(404, "Texture not found!").write(io.second) is BinaryPackage -> throw ConnectionUnexpectedPacketException()
close() // gets re-opened on next request. is ErrorPackage -> throw ConnectionErrorException(pkg)
throw IllegalArgumentException("Image Argument was needed.") else -> throw RuntimeException("Unreachable")
}
}
}
@Throws(IOException::class, ConnectionException::class)
fun getTextureByName(name: String): Texture? {
return withStreams { i, o ->
val obj = JsonObject()
obj.add("get_texture", {
val inner = JsonObject()
inner.addProperty("name", name)
inner
}())
JsonPackage(obj).write(o)
when (val pkg = Package.read(i)) {
is JsonPackage -> {
return@withStreams if (pkg.content.isJsonNull) {
null
} else {
try {
Gson()
.fromJson<InternalTexture>(pkg.content, InternalTexture::class.java)
.toTexture()
} catch (e: JsonSyntaxException) {
throw ConnectionInvalidJsonException()
}
} }
} }
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
}
@Throws(IOException::class, ConnectionException::class)
fun getTextureFile(hash: Sha256): ByteArray {
return withStreams { i, o ->
val obj = JsonObject()
obj.add("get_texture_file", {
val inner = JsonObject()
inner.addProperty("texture_hash", hash.toString())
inner
}())
JsonPackage(obj).write(o)
when (val pkg = Package.read(i)) {
is JsonPackage -> throw ConnectionUnexpectedPacketException()
is BinaryPackage -> return@withStreams pkg.content
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
}
@Throws(IOException::class, ConnectionException::class)
fun getTexturePreview(hash: Sha256): Image {
return withStreams { i, o ->
val obj = JsonObject()
obj.add("get_texture_preview", {
val inner = JsonObject()
inner.addProperty("texture_hash", hash.toString())
inner.addProperty("desired_format", "jpeg")
inner
}())
JsonPackage(obj).write(o)
when (val pkg = Package.read(i)) {
is JsonPackage -> throw ConnectionUnexpectedPacketException()
is BinaryPackage -> {
return@withStreams Image(ByteArrayInputStream(pkg.content))
}
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
}
}
}
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
private fun replaceTexture(old: Texture?, new: Texture?, image: ByteArray?) {
return withStreams { i, o ->
val obj = JsonObject()
obj.add("replace_texture", {
val inner = JsonObject()
if (old != null) {
inner.add("old", Gson().toJsonTree(InternalTexture(old), InternalTexture::class.java))
} else {
inner.add("old", null)
}
if (new != null) {
inner.add("new", Gson().toJsonTree(InternalTexture(new), InternalTexture::class.java))
} else {
inner.add("new", null)
}
inner
}())
JsonPackage(obj).write(o)
when (val pkg = Package.read(i)) {
is JsonPackage -> {
when {
pkg.content == JsonPrimitive(true) -> // everthing is fine!
return@withStreams
image != null -> {
// should be { "get_texture_file": { texture_hash : <Hash> }}
// we don't check, since there is no good way to handle it.
BinaryPackage(image).write(o)
when (val ipkg = Package.read(i)) {
is JsonPackage -> {
if (ipkg.content != JsonPrimitive(true)) {
// Protokoll Assertion failed
throw ConnectionUnexpectedPacketException()
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(ipkg)
else -> throw RuntimeException("Unreachable")
}
}
else -> {
ErrorPackage(404, "Texture not found!").write(o)
close() // gets re-opened on next request.
throw IllegalArgumentException("Image Argument was needed.")
}
}
}
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
} }
is BinaryPackage -> throw ConnectionUnexpectedPacketException()
is ErrorPackage -> throw ConnectionErrorException(pkg)
else -> throw RuntimeException("Unreachable")
} }
} }
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
fun uploadTexture(texture: Texture, image: ByteArray) { fun uploadTexture(texture: Texture, image: ByteArray) {
if (texture.textureHash != Sha256(image)) { if (texture.textureHash != Sha256(image)) {
throw IllegalArgumentException("Sha256 of Image does not Match with Texture.") throw IllegalArgumentException("Sha256 of Image does not Match with Texture.")
@ -285,7 +296,6 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
} }
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
fun updateTexture(old: Texture, new: Texture, image: ByteArray) { fun updateTexture(old: Texture, new: Texture, image: ByteArray) {
if (new.textureHash != Sha256(image)) { if (new.textureHash != Sha256(image)) {
throw IllegalArgumentException("Sha256 of Image does not Match with Texture.") throw IllegalArgumentException("Sha256 of Image does not Match with Texture.")
@ -295,26 +305,28 @@ class Connection(val address: InetAddress, val port: Int = 10796) : Closeable {
} }
@Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class) @Throws(IOException::class, ConnectionException::class, IllegalArgumentException::class)
@Synchronized
fun deleteTexture(texture: Texture) { fun deleteTexture(texture: Texture) {
replaceTexture(texture, null, null) replaceTexture(texture, null, null)
} }
@Throws(IOException::class) @Throws(IOException::class)
@Synchronized
override fun close() { override fun close() {
if (output != null) { try {
output!!.close() if (output != null) {
output = null output!!.close()
} output = null
if (input != null) { }
input!!.close() if (input != null) {
input = null input!!.close()
} input = null
if (socket != null) { }
socket!!.close() if (socket != null) {
socket = null socket!!.close()
socket = null
}
} catch (e: IOException) {
// Ignore
} }
} }
} }

View File

@ -30,7 +30,7 @@ internal data class InternalTexture(
resolution = arrayOf(tex.resolution.first, tex.resolution.second), resolution = arrayOf(tex.resolution.first, tex.resolution.second),
added_on = arrayOf( added_on = arrayOf(
tex.addedOn.get(Calendar.YEAR), // tex.addedOn.get(Calendar.YEAR), //
tex.addedOn.get(Calendar.MONTH), // tex.addedOn.get(Calendar.MONTH) + 1, //
tex.addedOn.get(Calendar.DAY_OF_MONTH) tex.addedOn.get(Calendar.DAY_OF_MONTH)
), ),
texture_hash = tex.textureHash.toString() texture_hash = tex.textureHash.toString()
@ -50,7 +50,7 @@ internal data class InternalTexture(
else -> throw ConnectionInvalidJsonException() else -> throw ConnectionInvalidJsonException()
}, },
resolution = Pair(resolution[0], resolution[1]), resolution = Pair(resolution[0], resolution[1]),
addedOn = GregorianCalendar(added_on[0], added_on[1], added_on[2]), addedOn = GregorianCalendar(added_on[0], added_on[1] - 1, added_on[2]),
textureHash = Sha256(texture_hash) textureHash = Sha256(texture_hash)
) )
} catch (e: Exception) { // i Know, but no time :[] } catch (e: Exception) { // i Know, but no time :[]

View File

@ -6,7 +6,7 @@ import java.lang.Exception
sealed class ConnectionException(override val message: String) : Exception(message) sealed class ConnectionException(override val message: String) : Exception(message)
class ConnectionErrorException(val errorCode: Int, val errorMessage: String) : class ConnectionErrorException(errorCode: Int, errorMessage: String) :
ConnectionException("$errorCode $errorMessage") { ConnectionException("$errorCode $errorMessage") {
internal constructor(err: ErrorPackage) : this(err.code, err.message) internal constructor(err: ErrorPackage) : this(err.code, err.message)
} }

View File

@ -13,7 +13,7 @@ enum class TextureFormat {
data class Texture( data class Texture(
val id : UUID, val id : UUID,
val name : String, val name : String,
val tags : Array<String>, var tags : Array<String>,
val format : TextureFormat, val format : TextureFormat,
val resolution : Pair<Int, Int>, val resolution : Pair<Int, Int>,
val addedOn : Calendar, val addedOn : Calendar,

View File

@ -12,9 +12,11 @@ import javafx.scene.layout.BackgroundFill
import javafx.scene.layout.CornerRadii import javafx.scene.layout.CornerRadii
import javafx.scene.layout.VBox import javafx.scene.layout.VBox
import javafx.scene.paint.Paint import javafx.scene.paint.Paint
import tornadofx.* import tornadofx.addClass
import tornadofx.find
import tornadofx.paddingTop
class GUIModel constructor(var data: Texture, img: Image) : VBox(){ class GUIModel constructor(var data: Texture, img: Image) : VBox() {
private var image = ImageView() private var image = ImageView()
private var label = Label() private var label = Label()
@ -22,13 +24,13 @@ class GUIModel constructor(var data: Texture, img: Image) : VBox(){
private var exportItem = MenuItem("exportiern") private var exportItem = MenuItem("exportiern")
private var deleteItem = MenuItem("löschen") private var deleteItem = MenuItem("löschen")
private val gmc = find(GUIModelController::class) private val gmc = find(GUIModelController::class)
init { init {
super.setPadding(Insets(5.0, 5.0, 5.0, 5.0)) super.setPadding(Insets(5.0, 5.0, 5.0, 5.0))
super.getChildren().addAll(image, label) super.getChildren().addAll(image, label)
super.setOnContextMenuRequested { p0 -> contextMenu.show(this@GUIModel, p0.screenX, p0.screenY) } super.setOnContextMenuRequested { p0 -> contextMenu.show(this@GUIModel, p0.screenX, p0.screenY) }
super.setOnMouseClicked{ super.setOnMouseClicked {
if (gmc.isLastSelectedInitialized()) { if (gmc.isLastSelectedInitialized()) {
gmc.lastSelected.background = Background.EMPTY gmc.lastSelected.background = Background.EMPTY
this.background = Background(BackgroundFill(Paint.valueOf("#2b7bbb"), CornerRadii.EMPTY, Insets.EMPTY)) this.background = Background(BackgroundFill(Paint.valueOf("#2b7bbb"), CornerRadii.EMPTY, Insets.EMPTY))
@ -38,13 +40,22 @@ class GUIModel constructor(var data: Texture, img: Image) : VBox(){
gmc.lastSelected = this gmc.lastSelected = this
} }
gmc.previewSelectedAction(data) gmc.previewSelectedAction(data)
gmc.setSelected(this)
} }
label.addClass("metadata")
label.paddingTop = 5.0 label.paddingTop = 5.0
label.prefWidth = 128.0 label.prefWidth = 128.0
label.alignment = Pos.CENTER label.alignment = Pos.CENTER
label.text = data.name
label.background = Background(BackgroundFill(Paint.valueOf("#FFFF2b"), CornerRadii.EMPTY, Insets.EMPTY)) label.text = if (data.name.length > 15) {
"${data.name.subSequence(0, 14)}.."
} else {
data.name
}
label.background = Background(BackgroundFill(Paint.valueOf("#3a3a3a"), CornerRadii.EMPTY, Insets.EMPTY))
image.fitHeight = 128.0 image.fitHeight = 128.0
image.fitWidth = 128.0 image.fitWidth = 128.0
@ -55,7 +66,7 @@ class GUIModel constructor(var data: Texture, img: Image) : VBox(){
} }
deleteItem.setOnAction { deleteItem.setOnAction {
gmc.delete(data) gmc.delete()
} }
contextMenu.items.add(exportItem) contextMenu.items.add(exportItem)

View File

@ -3,7 +3,7 @@ package org.hso.texturesyncclient.model
import org.hso.texturesyncclient.controller.RootController import org.hso.texturesyncclient.controller.RootController
import tornadofx.Controller import tornadofx.Controller
class GUIModelController: Controller() { class GUIModelController : Controller() {
private val rootc = find(RootController::class) private val rootc = find(RootController::class)
@ -14,11 +14,15 @@ class GUIModelController: Controller() {
rootc.exportTexture(data) rootc.exportTexture(data)
} }
fun delete(data: Texture) { fun delete() {
rootc.deleteTexture(data) rootc.deleteTexture()
} }
fun previewSelectedAction(data: Texture) { fun previewSelectedAction(data: Texture) {
rootc.showDetail(data) rootc.showDetail(data)
} }
fun setSelected(model: GUIModel) {
rootc.setSelectedTexture(model)
}
} }

View File

@ -10,25 +10,30 @@ import javafx.scene.layout.BackgroundFill
import javafx.scene.layout.CornerRadii import javafx.scene.layout.CornerRadii
import javafx.scene.paint.Paint import javafx.scene.paint.Paint
import javafx.scene.layout.Priority import javafx.scene.layout.Priority
import org.hso.texturesyncclient.view.mainView.Preview3D
import tornadofx.* import tornadofx.*
class ImportView : View() { class ImportView : View("TextureSync") {
val tfFilePath = JFXTextField() val tfFilePath = JFXTextField()
val tfName = JFXTextField() val tfName = JFXTextField()
val cvTags = JFXChipView<String>() val cvTags = JFXChipView<String>()
val btnImport = JFXButton("Importieren") val btnImport = JFXButton("Importieren")
val btnBack = JFXButton("Zurück")
val preview = Preview3D()
private val btnBack = JFXButton("Zurück")
private val ivc: ImportViewController by inject() private val ivc: ImportViewController by inject()
init { init {
btnImport.isVisible = false btnImport.isVisible = false
preview.root.isVisible = false
} }
override val root = borderpane { override val root = borderpane {
minWidth = 1000.0 prefWidth = FX.primaryStage.width
minHeight = 500.0 prefHeight = FX.primaryStage.height
background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY)) background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY))
center = vbox(50) { center = vbox(50) {
@ -39,6 +44,8 @@ class ImportView : View() {
style = "-fx-font: 20px Verdana; -fx-text-fill: #2b7bbb;" style = "-fx-font: 20px Verdana; -fx-text-fill: #2b7bbb;"
} }
add(preview)
vbox(20) { vbox(20) {
hbox(10) { hbox(10) {
add(tfFilePath) add(tfFilePath)
@ -85,7 +92,7 @@ class ImportView : View() {
cvTags.style = "-fx-background-color: #53585b; -fx-text-inner-color: #b15b2e;" cvTags.style = "-fx-background-color: #53585b; -fx-text-inner-color: #b15b2e;"
//TODO change color of Chip´s see: https://github.com/jfoenixadmin/JFoenix/blob/master/jfoenix/src/main/resources/com/jfoenix/assets/css/controls/jfx-chip-view.css#L52 //TODO change color of Chip´s see: https://github.com/jfoenixadmin/JFoenix/blob/master/jfoenix/src/main/resources/com/jfoenix/assets/css/controls/jfx-chip-view.css#L52
btnImport.style = "-fx-button-type: RAISED; -fx-background-color: #b15b2e; -fx-text-fill: #3c3f41;" btnImport.style = "-fx-button-type: RAISED; -fx-background-color: #b15b2e; -fx-text-fill: #3c3f41; -fx-font-size: 15;"
btnBack.style = "-fx-button-type: RAISED; -fx-background-color: #3c3f41; -fx-text-fill: #2b7bbb; -fx-padding: 10;" btnBack.style = "-fx-button-type: RAISED; -fx-background-color: #3c3f41; -fx-text-fill: #2b7bbb; -fx-padding: 10;"
} }

View File

@ -1,9 +1,11 @@
package org.hso.texturesyncclient.view.importView package org.hso.texturesyncclient.view.importView
import javafx.scene.image.Image
import javafx.stage.FileChooser
import org.hso.texturesyncclient.controller.RootController import org.hso.texturesyncclient.controller.RootController
import tornadofx.Controller import tornadofx.Controller
import javafx.stage.FileChooser
import java.io.File import java.io.File
import java.io.FileInputStream
class ImportViewController : Controller() { class ImportViewController : Controller() {
@ -29,15 +31,25 @@ class ImportViewController : Controller() {
iv.tfFilePath.text = file.absolutePath iv.tfFilePath.text = file.absolutePath
iv.tfName.text = file.nameWithoutExtension iv.tfName.text = file.nameWithoutExtension
lastImportDir = file.parent.toString() //store last user chosen dir lastImportDir = file.parent.toString() //store last user chosen dir
runAsync {
try {
val fileInput = FileInputStream(file.absolutePath)
val img = Image(fileInput)
iv.preview.setTexture(img)
iv.preview.root.isVisible = true
} catch (e: Exception) {
// Got a catch'em all
println(e.message)
}
}
} }
} }
fun btnImportAction() { fun btnImportAction() {
rootc.importTexture(iv.tfFilePath.text, iv.tfName.text, iv.cvTags.chips) rootc.importTexture(iv.tfFilePath.text, iv.tfName.text, iv.cvTags.chips)
rootc.switchImportToMain() RootController.switchImportToMain(true)
iv.tfFilePath.clear() reset()
iv.tfName.clear()
iv.cvTags.chips.clear()
} }
fun validateImport() { fun validateImport() {
@ -46,9 +58,14 @@ class ImportViewController : Controller() {
} }
fun btnBackAction() { fun btnBackAction() {
rootc.switchImportToMain() RootController.switchImportToMain(false)
reset()
}
private fun reset() {
iv.tfFilePath.clear() iv.tfFilePath.clear()
iv.tfName.clear() iv.tfName.clear()
iv.cvTags.chips.clear() iv.cvTags.chips.clear()
iv.preview.root.isVisible = false
} }
} }

View File

@ -2,10 +2,9 @@ package org.hso.texturesyncclient.view.mainView
import com.jfoenix.controls.JFXButton import com.jfoenix.controls.JFXButton
import com.jfoenix.controls.JFXChipView import com.jfoenix.controls.JFXChipView
import com.jfoenix.controls.JFXTextField
import javafx.geometry.Insets import javafx.geometry.Insets
import javafx.geometry.Orientation import javafx.geometry.Orientation
import javafx.geometry.Pos
import javafx.scene.control.Label
import javafx.scene.image.Image import javafx.scene.image.Image
import javafx.scene.layout.Background import javafx.scene.layout.Background
import javafx.scene.layout.BackgroundFill import javafx.scene.layout.BackgroundFill
@ -13,59 +12,69 @@ import javafx.scene.layout.CornerRadii
import javafx.scene.paint.Paint import javafx.scene.paint.Paint
import tornadofx.* import tornadofx.*
class DetailView: View() { class DetailView : View() {
private val mvc: MainViewController by inject()
val preview = Preview3D() val preview = Preview3D()
val metaLabel = Label("Auflösung: 8MP\nName: Texture.png\nAndere: was anderes")
val cvTags = JFXChipView<String>() val cvTags = JFXChipView<String>()
val btnImport = JFXButton("+")
init { val nameInfo = JFXTextField().addClass("metadata")
// set a default texture val resolutionInfo = label().addClass("metadata")
preview.setTexture(Image("textures/sample_texture_1.jpg")) val formatInfo = label().addClass("metadata")
val dateInfo = label().addClass("metadata")
val btnSubmit = JFXButton("Ändern").addClass("btn-blue")
val metadataPanel = gridpane {
row {
label("Name ").addClass("metadata")
add(nameInfo)
}
row {
label("Auflösung ").addClass("metadata")
add(resolutionInfo)
}
row {
label("Format ").addClass("metadata")
add(formatInfo)
}
row {
label("Einfügedatum ").addClass("metadata")
add(dateInfo)
}
} }
override val root = form { override val root = form {
minWidth = 250.0 minWidth = 250.0
background = Background(BackgroundFill(Paint.valueOf("#9f9f9f"), CornerRadii.EMPTY, Insets.EMPTY)) background = Background(BackgroundFill(Paint.valueOf("#3a3a3a"), CornerRadii.EMPTY, Insets.EMPTY))
fieldset(labelPosition = Orientation.VERTICAL) { fieldset(labelPosition = Orientation.VERTICAL) {
field{ field {
vbox(7) { vbox(7) {
add(preview) add(preview)
} }
} }
field("Meta") { field {
add(metaLabel) add(metadataPanel)
} }
field { field {
minHeight = 145.0 minHeight = 155.0
add(cvTags) add(cvTags)
} }
field { field {
hbox(alignment = Pos.CENTER_RIGHT) { add(btnSubmit)
add(btnImport)
}
} }
// TODO add "Import" Btn
} }
}
style { init {
cvTags.minHeight = 135.0 // set a default texture
cvTags.paddingAll = 3.0 preview.setTexture(Image("icons/TextureSync_Icon_256x256.jpeg"))
cvTags.style = "-fx-background-color: #53585b; -fx-text-inner-color: #b15b2e;" btnSubmit.useMaxWidth = true
btnImport.buttonType = JFXButton.ButtonType.RAISED
btnImport.styleClass.add("jfx-floating-action-button");
}
} }
} }

View File

@ -13,12 +13,7 @@ class FolderView : View("FolderView"){
hgap = 5.0 hgap = 5.0
vgap = 5.0 vgap = 5.0
paddingAll = 10.0 paddingAll = 10.0
prefWidth = 732.0
prefHeight = 401.0
background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY)) background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY))
style {
}
} }
} }

View File

@ -1,8 +1,8 @@
package org.hso.texturesyncclient.view.mainView package org.hso.texturesyncclient.view.mainView
import com.jfoenix.controls.JFXButton
import com.jfoenix.controls.JFXChipView import com.jfoenix.controls.JFXChipView
import javafx.geometry.Insets import javafx.geometry.Insets
import javafx.scene.control.ScrollPane
import javafx.scene.layout.Background import javafx.scene.layout.Background
import javafx.scene.layout.BackgroundFill import javafx.scene.layout.BackgroundFill
@ -10,53 +10,60 @@ import javafx.scene.layout.CornerRadii
import javafx.scene.paint.Paint import javafx.scene.paint.Paint
import tornadofx.* import tornadofx.*
class MainView : View() { class MainView : View("TextureSync") {
val cvSearch = JFXChipView<String>() val cvSearch = JFXChipView<String>()
private val btnImport = JFXButton("+")
val folderView = find(FolderView::class) val folderView = find(FolderView::class)
val detailView = find(DetailView::class) val detailView = find(DetailView::class)
private val mvc: MainViewController by inject() private val mvc: MainViewController by inject()
override val root = borderpane { fun repeatSearch() {
mvc.cvSearchAction(cvSearch.chips)
}
override val root = anchorpane {
background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY)) background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY))
minWidth = 1000.0 prefWidth = FX.primaryStage.width
maxWidth = 1000.0 prefHeight = FX.primaryStage.height
minHeight = 500.0
maxHeight = 500.0
left = vbox { borderpane {
//background = Background(BackgroundFill(Paint.valueOf("#2b2b2b"), CornerRadii.EMPTY, Insets.EMPTY)) right = detailView.root
anchorpane{ center = vbox {
this.fitToParentWidth()
paddingAll = 5.0
add(cvSearch) add(cvSearch)
}
anchorpane {
scrollpane { scrollpane {
this.fitToParentSize()
this.vbarPolicy = ScrollPane.ScrollBarPolicy.ALWAYS
add(folderView.root)
style = "-fx-background-color:transparent;" style = "-fx-background-color:transparent;"
isFitToWidth = true
isFitToHeight = true
add(folderView.root)
} }
} }
anchorpaneConstraints {
topAnchor = 0
bottomAnchor = 0
rightAnchor = 0
leftAnchor = 0
}
} }
right = detailView.root add(btnImport)
style { style {
cvSearch.promptText = "Suche"
cvSearch.paddingAll = 5.0 cvSearch.paddingAll = 5.0
cvSearch.minHeight = 70.0 cvSearch.minHeight = 65.0
cvSearch.style = "-fx-background-color: #53585b; -fx-text-inner-color: #b15b2e;" cvSearch.style = "-fx-background-color: #53585b; -fx-text-inner-color: #b15b2e;"
cvSearch.anchorpaneConstraints {
topAnchor = 3
bottomAnchor = 3
leftAnchor = 3
rightAnchor = -5
}
btnImport.buttonType = JFXButton.ButtonType.RAISED
btnImport.styleClass.add("jfx-floating-action-button")
btnImport.anchorpaneConstraints {
bottomAnchor = 5
rightAnchor = 5
}
} }
// actions // actions
@ -64,14 +71,33 @@ class MainView : View() {
mvc.cvSearchAction(cvSearch.chips) mvc.cvSearchAction(cvSearch.chips)
} }
detailView.cvTags.chips.onChange { btnImport.setOnAction {
mvc.updateTags()
}
detailView.btnImport.setOnAction {
mvc.btnImportAction() mvc.btnImportAction()
} }
// TODO: on chipview update on name update
detailView.cvTags.chips.onChange {
detailView.btnSubmit.isVisible = true
}
detailView.nameInfo.textProperty().onChange {
detailView.btnSubmit.isVisible = true
}
detailView.btnSubmit.setOnAction {
mvc.updateTags()
detailView.btnSubmit.isVisible = false
}
//keyboard actions
shortcut("Ctrl+I") {
mvc.btnImportAction()
}
shortcut("Ctrl+E") {
mvc.scExport()
}
} }
} }

View File

@ -2,10 +2,10 @@ package org.hso.texturesyncclient.view.mainView
import javafx.collections.ObservableList import javafx.collections.ObservableList
import javafx.scene.image.Image import javafx.scene.image.Image
import org.hso.texturesyncclient.model.GUIModel
import tornadofx.Controller
import org.hso.texturesyncclient.controller.RootController import org.hso.texturesyncclient.controller.RootController
import org.hso.texturesyncclient.model.GUIModel
import org.hso.texturesyncclient.model.Texture import org.hso.texturesyncclient.model.Texture
import tornadofx.Controller
class MainViewController : Controller() { class MainViewController : Controller() {
@ -17,7 +17,6 @@ class MainViewController : Controller() {
// DetailView elements // DetailView elements
private val preview = mv.detailView.preview private val preview = mv.detailView.preview
private val metaLabel = mv.detailView.metaLabel
private val cvTags = mv.detailView.cvTags private val cvTags = mv.detailView.cvTags
private var lockUpdate: Boolean = false //lock update func when the system changes the detailview chipview private var lockUpdate: Boolean = false //lock update func when the system changes the detailview chipview
@ -26,18 +25,18 @@ class MainViewController : Controller() {
folderView.children.add(element) folderView.children.add(element)
} }
fun addAllElements(elementList: ArrayList<GUIModel>) {
folderView.children.addAll(elementList)
}
// DetailView functions // DetailView functions
fun setPreview3DTexture(img: Image) { fun setPreview3DTexture(img: Image) {
preview.setTexture(img) preview.setTexture(img)
} }
fun setMeta(name: String, res: String, etc: String) { fun setMeta(name: String, res: String, format: String, date: String) {
metaLabel.text = "Name: $name\nAuflösung: $res\nAnderes: $etc" with(mv.detailView) {
nameInfo.text = name
formatInfo.text = format
resolutionInfo.text = res
dateInfo.text = date
}
} }
fun setTags(chips: ObservableList<String>) { fun setTags(chips: ObservableList<String>) {
@ -47,19 +46,28 @@ class MainViewController : Controller() {
lockUpdate = true //allow update with onChange lockUpdate = true //allow update with onChange
} }
fun getTags(): ObservableList<String> {
return cvTags.chips
}
fun updateTags() { fun updateTags() {
if (lockUpdate) { //the chipView was changed by the user if (lockUpdate) { //the chipView was changed by the user
println("Tags changed") println("Tags changed")
rootc.updateTexture(cvTags.chips) rootc.updateTexture(
tags = cvTags.chips.toTypedArray(),
name = mv.detailView.nameInfo.text
)
} }
} }
// DetailView actions // MainView actions
fun cvSearchAction(tags: ObservableList<String>) { fun cvSearchAction(tags: ObservableList<String>) {
// show spinner, block ui // show spinner, block ui
folderView.children.clear() folderView.children.clear()
mv.cvSearch.isDisable = true mv.cvSearch.isDisable = true
setPreview3DTexture(Image("icons/TextureSync_Icon_256x256.jpeg")) // reset the 3DPreview to the logo
RootController.selectedTexture = null
runAsync { runAsync {
rootc.queryElements(tags) rootc.queryElements(tags)
@ -70,15 +78,29 @@ class MainViewController : Controller() {
} }
fun btnImportAction() { fun btnImportAction() {
rootc.switchMainToImport() RootController.switchMainToImport()
} }
fun removeTextureFromView(data: Texture) { fun removeTextureFromView(data: Texture) {
// stream all children nodes, filter them as GUIModel with data.id == data.id, for any found object if it's still present remove it from the folderView // stream all children nodes, filter them as GUIModel with data.id == data.id, for any found object if it's still present remove it from the folderView
folderView.children.stream().filter { x -> (x as GUIModel).data.id == data.id }.findAny() folderView.children.stream().filter { x -> (x as GUIModel).data.id == data.id }.findAny()
.ifPresent { x -> folderView.children.remove(x) } .ifPresent { x -> folderView.children.remove(x) }
} }
fun setVisibleMetaTags(bool: Boolean) {
if (bool) {
mv.detailView.metadataPanel.isVisible = true
mv.detailView.btnSubmit.isVisible = false
cvTags.isVisible = true
} else {
mv.detailView.metadataPanel.isVisible = false
mv.detailView.btnSubmit.isVisible = false
cvTags.isVisible = false
}
}
fun scExport() {
RootController.selectedTexture?.let { rootc.exportTexture(RootController.selectedTexture!!) }
}
} }

View File

@ -36,7 +36,6 @@ class Preview3D : View("Preview3D") {
pointLightFront.rotate = 90.0 pointLightFront.rotate = 90.0
} }
override val root = stackpane { override val root = stackpane {
add(dBox).apply { add(dBox).apply {
@ -56,7 +55,7 @@ class Preview3D : View("Preview3D") {
style { style {
minWidth = 200.px minWidth = 200.px
minHeight = 200.px minHeight = 200.px
background = Background(BackgroundFill(Color.BLUEVIOLET, CornerRadii.EMPTY, Insets.EMPTY)) background = Background(BackgroundFill(Color.valueOf("#3a3a3a"), CornerRadii.EMPTY, Insets.EMPTY))
} }
} }

View File

@ -13,7 +13,7 @@ import javafx.scene.layout.CornerRadii
import javafx.scene.paint.Paint import javafx.scene.paint.Paint
import tornadofx.* import tornadofx.*
class StartupView : View("StartupView") { class StartupView : View("TextureSync") {
val labelStatus = Label("Verbindung zum Server einrichten") val labelStatus = Label("Verbindung zum Server einrichten")
val spinnerStatus = JFXSpinner() val spinnerStatus = JFXSpinner()
@ -22,6 +22,7 @@ class StartupView : View("StartupView") {
private val svc: StartupViewController by inject() private val svc: StartupViewController by inject()
override val root = borderpane { override val root = borderpane {
minWidth = 1000.0 minWidth = 1000.0
minHeight = 500.0 minHeight = 500.0

View File

@ -1,7 +1,6 @@
package org.hso.texturesyncclient.view.startupView package org.hso.texturesyncclient.view.startupView
import org.hso.texturesyncclient.controller.RootController import org.hso.texturesyncclient.controller.RootController
import org.hso.texturesyncclient.controller.SettingsController
import tornadofx.Controller import tornadofx.Controller
@ -10,9 +9,8 @@ class StartupViewController : Controller() {
private val sv = find(StartupView::class) private val sv = find(StartupView::class)
private val rootc = find(RootController::class) private val rootc = find(RootController::class)
init { fun initConnection() {
println("init StartupViewController") println("init StartupViewController")
SettingsController.init()
startConnectionUI() startConnectionUI()
runAsync { runAsync {
rootc.initConnection(" ") rootc.initConnection(" ")
@ -23,7 +21,7 @@ class StartupViewController : Controller() {
} }
fun setServerAddress(address: String) { fun setServerAddress(address: String) {
sv.tfServerIP.text = address //sv.tfServerIP.text = address
sv.tfServerIP.isFocusTraversable = false sv.tfServerIP.isFocusTraversable = false
} }

View File

@ -88,5 +88,58 @@
-fx-min-height: -fx-pref-height; -fx-min-height: -fx-pref-height;
-fx-max-height: -fx-pref-height; -fx-max-height: -fx-pref-height;
-jfx-button-type: RAISED; -jfx-button-type: RAISED;
-fx-font-size: 25px
-fx-text-inner-color: #2b2b2b;
-fx-font-size: 20px;
} }
/*******************************************************************************
* *
* ChipView *
* *
******************************************************************************/
.jfx-chip-view .jfx-chip > HBox {
-fx-font-family: "Roboto Medium";
-fx-font-size: 14.0;
-fx-background-color: #E0E0E0;
-fx-background-radius: 40px;
-fx-padding: 5px 8px 5px 12px;
-fx-pref-height: 32px;
-fx-alignment: center-left;
-fx-spacing: 8;
}
.jfx-chip-view {
-fx-text-inner-color: #E0E0E0;
}
/*******************************************************************************
* *
* Buttons *
* *
******************************************************************************/
.btn-blue {
-fx-button-type: RAISED;
-fx-background-color: #3c3f41;
-fx-text-fill: #2b7bbb;
-fx-padding: 10;
}
.btn-orange {
-fx-button-type: RAISED;
-fx-background-color: #b15b2e;
-fx-text-fill: #3c3f41;
}
/*******************************************************************************
* *
* DetailView *
* *
******************************************************************************/
.metadata {
-fx-font: 14px Verdana;
-fx-text-fill: #E0E0E0;
}

View File

@ -0,0 +1 @@
<svg width="640" height="640" xmlns="http://www.w3.org/2000/svg"><defs><radialGradient id="a" cx="0.2" cy="-0.5" r="1.7"><stop offset="40%" stop-color="#8c8c8c"/><stop offset="100%" stop-color="#4c4c4c"/></radialGradient><radialGradient id="b" cx="0.2" cy="0.2" fx="0.34" fy="0.32" r="0.9"><stop offset="0%" stop-color="#fbf6f0"/><stop offset="50%" stop-color="#eadec4"/><stop offset="100%" stop-color="#aba390"/></radialGradient><radialGradient id="c" cx="0.2" cy="0.2" fx="0.34" fy="0.32" r="0.9"><stop offset="5%" stop-color="#fbf1cd"/><stop offset="50%" stop-color="#ffba00"/><stop offset="100%" stop-color="#bc8602"/></radialGradient></defs><path d="M158.58 102.89C144.48 110.79 143.14 130.93 155.49 141.35C169.62 153.27 184.17 164.75 199.13 175.69C138.27 240.95 105.0 337.14 105.0 426.0C105.0 525.49 179.5 590.92 278.99 591.0C342.5 591.05 406.69 553.62 449.59 506.78C501.0 450.65 531.88 370.14 532.0 294.02C532.06 254.61 524.06 213.61 505.46 178.86C487.92 146.11 450.51 118.09 413.38 117.01C388.12 116.27 362.24 125.41 340.98 139.06C331.11 145.4 321.78 152.65 313.04 160.6C313.88 131.47 312.82 102.25 309.97 73.31C308.35 56.96 293.5 46.31 277.86 51.34C236.62 64.58 196.37 81.72 158.58 102.89Z" fill="#000"/><path d="M165.42 115.11C158.26 119.12 158.24 125.36 164.51 130.65C201.33 161.71 241.11 189.73 283.36 212.86C290.09 216.54 295.26 213.92 296.04 206.29C300.48 162.65 300.34 118.34 296.03 74.69C295.17 65.95 290.5 61.98 282.14 64.66C241.79 77.63 202.4 94.39 165.42 115.11Z" fill="url(#a)"/><path d="M220.6 190.82C238.75 203.14 257.44 214.63 276.64 225.14C282.11 228.13 288.25 228.46 293.76 226.78L496.27 366.27C484.19 411.93 461.33 455.47 430.41 489.22C397.54 525.11 350.51 555.58 301.99 563.18L136.05 367.03C147.1 301.77 176.06 237.27 220.6 190.82Z" fill="url(#b)"/><path d="M293.76 226.78C302.1 224.23 309.01 217.1 309.96 207.71C310.21 205.29 310.44 202.86 310.66 200.43C323.57 185.24 338.43 171.6 355.02 160.94C371.91 150.09 392.56 142.41 412.62 142.99C440.73 143.82 469.27 166.35 482.54 191.14C499.13 222.12 506.06 258.84 506.0 293.98C505.96 317.93 502.59 342.39 496.27 366.27L330.0 369.0L301.99 563.18C294.35 564.38 286.68 565.01 279.01 565.0C192.51 564.93 131.0 512.5 131.0 426.0C131.0 406.59 132.7 386.78 136.05 367.03L290.0 332.0L293.76 226.78Z" fill="url(#c)"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,24 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text"> <office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
<office:meta><meta:creation-date>2019-03-22T18:11:56.768840842</meta:creation-date><dc:date>2019-03-29T13:15:18.356408709</dc:date><meta:editing-duration>PT3H5M45S</meta:editing-duration><meta:editing-cycles>98</meta:editing-cycles><meta:generator>LibreOffice/6.2.2.1$Linux_X86_64 LibreOffice_project/20$Build-1</meta:generator><dc:title>Charter</dc:title><meta:document-statistic meta:table-count="5" meta:image-count="0" meta:object-count="0" meta:page-count="3" meta:paragraph-count="86" meta:word-count="244" meta:character-count="1896" meta:non-whitespace-character-count="1746"/><meta:user-defined meta:name="Version">1.2.0</meta:user-defined></office:meta> <office:meta><meta:creation-date>2019-03-22T18:11:56.768840842</meta:creation-date><dc:date>2019-06-14T18:27:49.303971292</dc:date><meta:editing-duration>PT3H6M</meta:editing-duration><meta:editing-cycles>99</meta:editing-cycles><meta:generator>LibreOffice/6.2.3.2$Linux_X86_64 LibreOffice_project/20$Build-2</meta:generator><dc:title>Charter</dc:title><meta:document-statistic meta:table-count="5" meta:image-count="0" meta:object-count="0" meta:page-count="3" meta:paragraph-count="86" meta:word-count="244" meta:character-count="1896" meta:non-whitespace-character-count="1746"/><meta:user-defined meta:name="Version">1.2.0</meta:user-defined></office:meta>
<office:settings> <office:settings>
<config:config-item-set config:name="ooo:view-settings"> <config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="ViewAreaTop" config:type="long">38276</config:config-item> <config:config-item config:name="ViewAreaTop" config:type="long">67733</config:config-item>
<config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item> <config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaWidth" config:type="long">40924</config:config-item> <config:config-item config:name="ViewAreaWidth" config:type="long">39160</config:config-item>
<config:config-item config:name="ViewAreaHeight" config:type="long">17179</config:config-item> <config:config-item config:name="ViewAreaHeight" config:type="long">17244</config:config-item>
<config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item> <config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
<config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item> <config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
<config:config-item-map-indexed config:name="Views"> <config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry> <config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item> <config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="long">18648</config:config-item> <config:config-item config:name="ViewLeft" config:type="long">11077</config:config-item>
<config:config-item config:name="ViewTop" config:type="long">50045</config:config-item> <config:config-item config:name="ViewTop" config:type="long">74761</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item> <config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="long">38276</config:config-item> <config:config-item config:name="VisibleTop" config:type="long">67733</config:config-item>
<config:config-item config:name="VisibleRight" config:type="long">40922</config:config-item> <config:config-item config:name="VisibleRight" config:type="long">39158</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="long">55453</config:config-item> <config:config-item config:name="VisibleBottom" config:type="long">84975</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item> <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">1</config:config-item> <config:config-item config:name="ViewLayoutColumns" config:type="short">1</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item> <config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
@ -29,98 +29,98 @@
</config:config-item-map-indexed> </config:config-item-map-indexed>
</config:config-item-set> </config:config-item-set>
<config:config-item-set config:name="ooo:configuration-settings"> <config:config-item-set config:name="ooo:configuration-settings">
<config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintFaxName" config:type="string"/>
<config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item> <config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item> <config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item> <config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item> <config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item> <config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
<config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item> <config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item>
<config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item> <config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterSetup" config:type="base64Binary"/> <config:config-item config:name="PrintFaxName" config:type="string"/>
<config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">true</config:config-item>
<config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="DisableOffPagePositioning" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">false</config:config-item>
<config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item>
<config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item>
<config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item> <config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item>
<config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">192011</config:config-item> <config:config-item config:name="RsidRoot" config:type="int">192011</config:config-item>
<config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item> <config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
<config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item> <config:config-item config:name="PrinterName" config:type="string"/>
<config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
<config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item>
<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item>
<config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item> <config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item>
<config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedComplexScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
<config:config-item config:name="Rsid" config:type="int">7352283</config:config-item>
<config:config-item config:name="EmbeddedDatabaseName" config:type="string"/>
<config:config-item config:name="SaveThumbnail" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintEmptyPages" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item>
<config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item>
<config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
<config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item>
<config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item>
<config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
<config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/>
<config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item>
<config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item>
<config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
<config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item> <config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item> <config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
<config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
<config:config-item config:name="CurrentDatabaseCommand" config:type="string"/>
<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
<config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbeddedDatabaseName" config:type="string"/>
<config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item>
<config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterName" config:type="string"/>
<config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveThumbnail" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
<config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item>
<config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item> <config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item>
<config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item> <config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
<config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item>
<config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/>
<config:config-item config:name="EmbedComplexScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item> <config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseCommand" config:type="string"/>
<config:config-item config:name="PrinterSetup" config:type="base64Binary"/>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item> <config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="DisableOffPagePositioning" config:type="boolean">true</config:config-item>
<config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">false</config:config-item>
<config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="Rsid" config:type="int">7336954</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item>
<config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">true</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintEmptyPages" config:type="boolean">false</config:config-item>
</config:config-item-set> </config:config-item-set>
</office:settings> </office:settings>
<office:scripts> <office:scripts>
@ -122663,13 +122663,16 @@
<style:style style:name="P35" style:family="paragraph" style:parent-style-name="Table_20_Contents" style:list-style-name="L3"> <style:style style:name="P35" style:family="paragraph" style:parent-style-name="Table_20_Contents" style:list-style-name="L3">
<style:text-properties officeooo:rsid="006f78fd" officeooo:paragraph-rsid="006f78fd"/> <style:text-properties officeooo:rsid="006f78fd" officeooo:paragraph-rsid="006f78fd"/>
</style:style> </style:style>
<style:style style:name="P36" style:family="paragraph" style:parent-style-name="Table_20_Contents" style:list-style-name="L4"> <style:style style:name="P36" style:family="paragraph" style:parent-style-name="Table_20_Contents">
<style:text-properties officeooo:rsid="006f78fd" officeooo:paragraph-rsid="00702fdb"/>
</style:style>
<style:style style:name="P37" style:family="paragraph" style:parent-style-name="Table_20_Contents" style:list-style-name="L4">
<style:text-properties officeooo:rsid="0034c4ee" officeooo:paragraph-rsid="0034c4ee"/> <style:text-properties officeooo:rsid="0034c4ee" officeooo:paragraph-rsid="0034c4ee"/>
</style:style> </style:style>
<style:style style:name="P37" style:family="paragraph" style:parent-style-name="Heading_20_1" style:master-page-name=""> <style:style style:name="P38" style:family="paragraph" style:parent-style-name="Heading_20_1" style:master-page-name="">
<style:paragraph-properties style:page-number="auto" fo:break-before="auto" fo:break-after="auto"/> <style:paragraph-properties style:page-number="auto" fo:break-before="auto" fo:break-after="auto"/>
</style:style> </style:style>
<style:style style:name="P38" style:family="paragraph" style:parent-style-name="Title" style:master-page-name="First_20_Page"> <style:style style:name="P39" style:family="paragraph" style:parent-style-name="Title" style:master-page-name="First_20_Page">
<style:paragraph-properties style:page-number="auto"/> <style:paragraph-properties style:page-number="auto"/>
<style:text-properties officeooo:paragraph-rsid="0004b30c"/> <style:text-properties officeooo:paragraph-rsid="0004b30c"/>
</style:style> </style:style>
@ -122960,7 +122963,7 @@
<office:master-styles> <office:master-styles>
<style:master-page style:name="Standard" style:page-layout-name="pm1"> <style:master-page style:name="Standard" style:page-layout-name="pm1">
<style:footer> <style:footer>
<text:p text:style-name="P1"><text:span text:style-name="T1">TextureSync</text:span> <text:tab/><text:title>Charter</text:title> <text:span text:style-name="T2">⸬ </text:span><text:span text:style-name="T1">Version </text:span><text:user-defined style:data-style-name="N0" text:name="Version">1.2.0</text:user-defined><text:tab/><text:span text:style-name="T3">Seite</text:span> <text:page-number text:select-page="current">2</text:page-number>/<text:page-count>3</text:page-count></text:p> <text:p text:style-name="P1"><text:span text:style-name="T1">TextureSync</text:span> <text:tab/><text:title>Charter</text:title> <text:span text:style-name="T2">⸬ </text:span><text:span text:style-name="T1">Version </text:span><text:user-defined style:data-style-name="N0" text:name="Version">1.2.0</text:user-defined><text:tab/><text:span text:style-name="T3">Seite</text:span> <text:page-number text:select-page="current">3</text:page-number>/<text:page-count>3</text:page-count></text:p>
</style:footer> </style:footer>
</style:master-page> </style:master-page>
<style:master-page style:name="First_20_Page" style:display-name="First Page" style:page-layout-name="pm2" style:next-style-name="Standard"/> <style:master-page style:name="First_20_Page" style:display-name="First Page" style:page-layout-name="pm2" style:next-style-name="Standard"/>
@ -122977,7 +122980,7 @@
<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
<text:sequence-decl text:display-outline-level="0" text:name="Figure"/> <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
</text:sequence-decls> </text:sequence-decls>
<text:p text:style-name="P38"/> <text:p text:style-name="P39"/>
<text:p text:style-name="P17"/> <text:p text:style-name="P17"/>
<text:p text:style-name="Title"><text:title>Charter</text:title></text:p> <text:p text:style-name="Title"><text:title>Charter</text:title></text:p>
<text:p text:style-name="Subtitle">TextureSync</text:p> <text:p text:style-name="Subtitle">TextureSync</text:p>
@ -123094,7 +123097,7 @@
<text:p text:style-name="Table_20_Contents">Wichtigste Funktionen</text:p> <text:p text:style-name="Table_20_Contents">Wichtigste Funktionen</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tabelle2.B2" office:value-type="string"> <table:table-cell table:style-name="Tabelle2.B2" office:value-type="string">
<text:list xml:id="list1098403870" text:style-name="L1"> <text:list xml:id="list652413232" text:style-name="L1">
<text:list-item> <text:list-item>
<text:p text:style-name="P30">Texturen anzeigen und verwalten</text:p> <text:p text:style-name="P30">Texturen anzeigen und verwalten</text:p>
</text:list-item> </text:list-item>
@ -123118,7 +123121,7 @@
<text:p text:style-name="Table_20_Contents">Akzeptanzkriterien</text:p> <text:p text:style-name="Table_20_Contents">Akzeptanzkriterien</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tabelle2.B2" office:value-type="string"> <table:table-cell table:style-name="Tabelle2.B2" office:value-type="string">
<text:list xml:id="list846724402" text:style-name="L2"> <text:list xml:id="list868670440" text:style-name="L2">
<text:list-item> <text:list-item>
<text:p text:style-name="P31">Das Durchsuchen darf nicht länger als 1 Sekunde bei 1000 Texturen dauern.</text:p> <text:p text:style-name="P31">Das Durchsuchen darf nicht länger als 1 Sekunde bei 1000 Texturen dauern.</text:p>
</text:list-item> </text:list-item>
@ -123206,7 +123209,7 @@
<text:p text:style-name="P8">Projekt</text:p> <text:p text:style-name="P8">Projekt</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tabelle2.B2" office:value-type="string"> <table:table-cell table:style-name="Tabelle2.B2" office:value-type="string">
<text:list xml:id="list1130294127" text:style-name="L3"> <text:list xml:id="list4239375724" text:style-name="L3">
<text:list-item> <text:list-item>
<text:p text:style-name="P33"><text:span text:style-name="T11">u</text:span>nzureichende Aufwandsschätzungen</text:p> <text:p text:style-name="P33"><text:span text:style-name="T11">u</text:span>nzureichende Aufwandsschätzungen</text:p>
</text:list-item> </text:list-item>
@ -123224,7 +123227,7 @@
<text:p text:style-name="P8">Produkt</text:p> <text:p text:style-name="P8">Produkt</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tabelle2.B2" office:value-type="string"> <table:table-cell table:style-name="Tabelle2.B2" office:value-type="string">
<text:list xml:id="list192018566" text:style-name="L4"> <text:list xml:id="list1833401399" text:style-name="L4">
<text:list-item> <text:list-item>
<text:p text:style-name="P34">Dateiverlust</text:p> <text:p text:style-name="P34">Dateiverlust</text:p>
</text:list-item> </text:list-item>
@ -123232,10 +123235,10 @@
<text:p text:style-name="P34">Metadaten werden <text:span text:style-name="T11">vertauscht </text:span></text:p> <text:p text:style-name="P34">Metadaten werden <text:span text:style-name="T11">vertauscht </text:span></text:p>
</text:list-item> </text:list-item>
<text:list-item> <text:list-item>
<text:p text:style-name="P36">Verlust von Daten durch nicht-funktionierende Synchronisation</text:p> <text:p text:style-name="P37">Verlust von Daten durch nicht-funktionierende Synchronisation</text:p>
</text:list-item> </text:list-item>
<text:list-item> <text:list-item>
<text:p text:style-name="P36">„single point of failure“ durch Server-Architektur</text:p> <text:p text:style-name="P37">„single point of failure“ durch Server-Architektur</text:p>
</text:list-item> </text:list-item>
</text:list> </text:list>
</table:table-cell> </table:table-cell>
@ -123342,18 +123345,18 @@
</table:table-row> </table:table-row>
<table:table-row> <table:table-row>
<table:table-cell table:style-name="Tabelle5.A2" office:value-type="string"> <table:table-cell table:style-name="Tabelle5.A2" office:value-type="string">
<text:p text:style-name="P15">1.2.0</text:p> <text:p text:style-name="P15">1.1.0</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tabelle5.B2" office:value-type="string"> <table:table-cell table:style-name="Tabelle5.B2" office:value-type="string">
<text:p text:style-name="P15">Risiken überarbeitet, Einschränkungen bei Anzahl der Nutzer</text:p> <text:p text:style-name="P15">Changelog hinzugefügt</text:p>
</table:table-cell> </table:table-cell>
</table:table-row> </table:table-row>
<table:table-row> <table:table-row>
<table:table-cell table:style-name="Tabelle5.A3" office:value-type="string"> <table:table-cell table:style-name="Tabelle5.A3" office:value-type="string">
<text:p text:style-name="P15">1.1.0</text:p> <text:p text:style-name="P36">1.2.0</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tabelle5.B3" office:value-type="string"> <table:table-cell table:style-name="Tabelle5.B3" office:value-type="string">
<text:p text:style-name="P15">Changelog hinzugefügt</text:p> <text:p text:style-name="P36">Risiken überarbeitet, Einschränkungen bei Anzahl der Nutzer</text:p>
</table:table-cell> </table:table-cell>
</table:table-row> </table:table-row>
</table:table> </table:table>

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -1,111 +1,116 @@
<svg width="1337" height="1019" version="1.1" baseProfile="full" viewbox="0 0 1337 1019" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" style="font-weight:bold; font-size:12pt; font-family:'Calibri', Helvetica, sans-serif;;stroke-width:3;stroke-linejoin:round;stroke-linecap:round"><path d="M161 209.9 L13.5 284.5 L13.5 837.5 L13.5 837.5 L81 859.7 L81 859.7 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path> <svg width="1513" height="1004" version="1.1" baseProfile="full" viewbox="0 0 1513 1004" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" style="font-weight:bold; font-size:12pt; font-family:'Calibri', Helvetica, sans-serif;;stroke-width:3;stroke-linejoin:round;stroke-linecap:round"><path d="M229 180.3 L-26.5 269.5 L-26.5 546 L-26.5 546 L-26.5 822.5 L-26.5 822.5 L149 864.4 L149 864.4 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path>
<path d="M66.7 860.6 L74.7 857.6 L70 850.5 L81 859.7 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path> <path d="M134.8 866.5 L142.5 862.9 L137.3 856.1 L149 864.4 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
<path d="M301 264.5 L301 284.5 L301 304.5 L301 304.5 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path> <path d="M369 249.5 L369 269.5 L369 289.5 L369 289.5 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path>
<path d="M295.7 291.2 L301 297.8 L306.3 291.2 L301 304.5 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path> <path d="M363.7 276.2 L369 282.8 L374.3 276.2 L369 289.5 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
<path d="M441 170.1 L956.5 284.5 L956.5 327 L956.5 327 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path> <path d="M509 156.8 L1132.5 269.5 L1132.5 312 L1132.5 312 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path>
<path d="M951.2 313.7 L956.5 320.3 L961.8 313.7 L956.5 327 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path> <path d="M1127.2 298.7 L1132.5 305.3 L1137.8 298.7 L1132.5 312 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
<path d="M301 817.5 L301 837.5 L301 857.5 L301 857.5 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path> <path d="M369 802.5 L369 822.5 L369 842.5 L369 842.5 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path>
<path d="M295.7 844.2 L301 850.8 L306.3 844.2 L301 857.5 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path> <path d="M363.7 829.2 L369 835.8 L374.3 829.2 L369 842.5 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
<path d="M956.5 795 L956.5 837.5 L521 900.3 L521 900.3 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path> <path d="M1132.5 780 L1132.5 822.5 L589 889.8 L589 889.8 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path>
<path d="M533.4 893.1 L527.6 899.3 L535 903.7 L521 900.3 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path> <path d="M601.6 882.8 L595.6 889 L602.9 893.4 L589 889.8 Z" style="stroke:#33322E;fill:#33322E;stroke-dasharray:none;"></path>
<rect x="81.5" y="888.5" height="118" width="440" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <rect x="13.5" y="320.5" height="482" width="711" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<path d="M81.5 888.5 L81.5 857.5 L145 857.5 L145 888.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path> <path d="M13.5 320.5 L13.5 289.5 L105.5 289.5 L105.5 320.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path>
<text x="89.5" y="879" style="font-weight:normal;">model</text> <text x="21.5" y="311" style="font-weight:normal;">protocol</text>
<path d="M81.5 888.5 L521.5 888.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M13.5 320.5 L724.5 320.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<rect x="94.5" y="901.5" height="92" width="159" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <rect x="26.5" y="464.5" height="62" width="178" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="112.3" y="923" style="">«enumeration»</text> <text x="115.5" y="486" style="font-weight:normal;font-style:italic;text-anchor: middle;">+ ProtocolHandler</text>
<text x="102.8" y="938" style="">+ TextureFormat</text> <path d="M26.5 495.5 L204.5 495.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M94.5 947.5 L253.5 947.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="34.5" y="517" style="font-weight:normal;">...</text>
<text x="102.5" y="969" style="font-weight:normal;">JPEG</text> <rect x="31.5" y="696.5" height="62" width="168" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="102.5" y="984" style="font-weight:normal;">PNG</text> <text x="115.5" y="718" style="text-anchor: middle;">+ ProtocolConfig</text>
<rect x="293.5" y="916.5" height="62" width="102" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <path d="M31.5 727.5 L199.5 727.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="301.8" y="938" style="">+ Texture</text> <text x="39.5" y="749" style="font-weight:normal;">...</text>
<path d="M293.5 947.5 L395.5 947.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <rect x="239.5" y="727.5" height="31" width="472" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="301.5" y="969" style="font-weight:normal;">...</text> <path d="M239.5 727.5 L239.5 696.5 L360 696.5 L360 727.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path>
<rect x="435.5" y="916.5" height="62" width="73" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <text x="247.5" y="718" style="font-weight:normal;">autoconnect</text>
<text x="443.5" y="938" style="">Sha256</text> <path d="M239.5 727.5 L711.5 727.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M435.5 947.5 L508.5 947.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="247.5" y="749" style="font-weight:normal;">+ start_autoconnect_server(cfg : ProtocolConfig)</text>
<text x="443.5" y="969" style="font-weight:normal;">...</text> <rect x="350.5" y="364.5" height="292" width="251" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<rect x="588.5" y="358.5" height="437" width="736" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <path d="M350.5 364.5 L350.5 333.5 L423.5 333.5 L423.5 364.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path>
<path d="M588.5 358.5 L588.5 327.5 L709 327.5 L709 358.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path> <text x="358.5" y="355" style="font-weight:normal;">result</text>
<text x="596.5" y="349" style="font-weight:normal;">persistency</text> <path d="M350.5 364.5 L601.5 364.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M588.5 358.5 L1324.5 358.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <rect x="392.5" y="377.5" height="62" width="168" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<rect x="601.5" y="451.5" height="62" width="121" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <text x="476.5" y="399" style="text-anchor: middle;">+ ProtocolResult</text>
<text x="609.8" y="473" style="">+ DataStore</text> <path d="M392.5 408.5 L560.5 408.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M601.5 482.5 L722.5 482.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="400.5" y="430" style="font-weight:normal;">...</text>
<text x="609.5" y="504" style="font-weight:normal;">...</text> <rect x="396.5" y="479.5" height="62" width="159" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<rect x="762.5" y="402.5" height="190" width="223" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <text x="476" y="501" style="text-anchor: middle;">+ ProtocolError</text>
<path d="M762.5 402.5 L762.5 371.5 L835.5 371.5 L835.5 402.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path> <path d="M396.5 510.5 L555.5 510.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="770.5" y="393" style="font-weight:normal;">result</text> <text x="404.5" y="532" style="font-weight:normal;">...</text>
<path d="M762.5 402.5 L985.5 402.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <rect x="363.5" y="581.5" height="62" width="225" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<rect x="775.5" y="415.5" height="62" width="197" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <text x="476" y="603" style="text-anchor: middle;">+ ReplaceTextureStatus</text>
<text x="783.8" y="437" style="">+ TextureFileResult</text> <path d="M363.5 612.5 L588.5 612.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M775.5 446.5 L972.5 446.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="371.5" y="634" style="font-weight:normal;">...</text>
<text x="783.5" y="468" style="font-weight:normal;">...</text> <path d="M13.5 771.5 L724.5 771.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<rect x="780.5" y="517.5" height="62" width="187" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <text x="21.5" y="793" style="font-weight:normal;">+ listen_forever(handler : &amp;ProtocolHandler) : ...</text>
<text x="788.5" y="539" style="">+ TextureFileError</text> <rect x="229.5" y="44.5" height="205" width="280" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<path d="M780.5 548.5 L967.5 548.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M229.5 44.5 L229.5 13.5 L283.5 13.5 L283.5 44.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path>
<text x="788.5" y="570" style="font-weight:normal;">...</text> <text x="237.5" y="35" style="font-weight:normal;">main</text>
<rect x="1025.5" y="453.5" height="88" width="109" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <path d="M229.5 44.5 L509.5 44.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M1025.5 453.5 L1025.5 422.5 L1098.5 422.5 L1098.5 453.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path> <path d="M369.5 119.5 L369.5 139.5 L369.5 159.5 L369.5 159.5 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path>
<text x="1033.5" y="444" style="font-weight:normal;">search</text> <rect x="309.5" y="57.5" height="62" width="121" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<path d="M1025.5 453.5 L1134.5 453.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="370" y="79" style="text-anchor: middle;">ServerState</text>
<rect x="1038.5" y="466.5" height="62" width="83" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <path d="M309.5 88.5 L430.5 88.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="1046.8" y="488" style="">+ Query</text> <text x="317.5" y="110" style="font-weight:normal;">...</text>
<path d="M1038.5 497.5 L1121.5 497.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M242.5 159.5 L488.5 159.5 L496.5 167.5 L496.5 205.5 L242.5 205.5 L242.5 159.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path>
<text x="1046.5" y="519" style="font-weight:normal;">...</text> <path d="M488.5 159.5 L488.5 167.5 L496.5 167.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<rect x="848.5" y="663.5" height="119" width="463" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <text x="250.5" y="181" style="font-weight:normal;">implements</text>
<path d="M848.5 663.5 L848.5 632.5 L988 632.5 L988 663.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path> <text x="250.5" y="196" style="font-weight:normal;">protocol::ProtocolHandler</text>
<text x="856.5" y="654" style="font-weight:normal;">image_convert</text> <path d="M229.5 218.5 L509.5 218.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M848.5 663.5 L1311.5 663.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="237.5" y="240" style="font-weight:normal;">+ main()</text>
<rect x="861.5" y="676.5" height="62" width="159" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <rect x="149.5" y="873.5" height="118" width="440" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<text x="869.8" y="698" style="">+ ConvertConfig</text> <path d="M149.5 873.5 L149.5 842.5 L213 842.5 L213 873.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path>
<path d="M861.5 707.5 L1020.5 707.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="157.5" y="864" style="font-weight:normal;">model</text>
<text x="869.5" y="729" style="font-weight:normal;">...</text> <path d="M149.5 873.5 L589.5 873.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M848.5 751.5 L1311.5 751.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <rect x="162.5" y="886.5" height="92" width="159" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="856.5" y="773" style="font-weight:normal;">+ generate_preview(input, format, config) : ...</text> <text x="242" y="908" style="text-anchor: middle;">«enumeration»</text>
<rect x="53.5" y="335.5" height="482" width="495" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <text x="242" y="923" style="text-anchor: middle;">+ TextureFormat</text>
<path d="M53.5 335.5 L53.5 304.5 L145.5 304.5 L145.5 335.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path> <path d="M162.5 932.5 L321.5 932.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="61.5" y="326" style="font-weight:normal;">protocol</text> <text x="170.5" y="954" style="font-weight:normal;">JPEG</text>
<path d="M53.5 335.5 L548.5 335.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="170.5" y="969" style="font-weight:normal;">PNG</text>
<rect x="66.5" y="479.5" height="62" width="178" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <rect x="361.5" y="901.5" height="62" width="102" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="74.8" y="501" style="font-weight:normal;font-style:italic;">+ ProtocolHandler</text> <text x="412.5" y="923" style="text-anchor: middle;">+ Texture</text>
<path d="M66.5 510.5 L244.5 510.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M361.5 932.5 L463.5 932.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="74.5" y="532" style="font-weight:normal;">...</text> <text x="369.5" y="954" style="font-weight:normal;">...</text>
<rect x="71.5" y="711.5" height="62" width="168" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <rect x="503.5" y="901.5" height="62" width="73" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="79.5" y="733" style="">+ ProtocolConfig</text> <text x="540" y="923" style="text-anchor: middle;">Sha256</text>
<path d="M71.5 742.5 L239.5 742.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M503.5 932.5 L576.5 932.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="79.5" y="764" style="font-weight:normal;">...</text> <text x="511.5" y="954" style="font-weight:normal;">...</text>
<rect x="284.5" y="379.5" height="292" width="251" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <rect x="764.5" y="343.5" height="437" width="736" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<path d="M284.5 379.5 L284.5 348.5 L357.5 348.5 L357.5 379.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path> <path d="M764.5 343.5 L764.5 312.5 L885 312.5 L885 343.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path>
<text x="292.5" y="370" style="font-weight:normal;">result</text> <text x="772.5" y="334" style="font-weight:normal;">persistency</text>
<path d="M284.5 379.5 L535.5 379.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M764.5 343.5 L1500.5 343.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<rect x="326.5" y="392.5" height="62" width="168" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <rect x="1024.5" y="648.5" height="119" width="463" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="334.5" y="414" style="">+ ProtocolResult</text> <path d="M1024.5 648.5 L1024.5 617.5 L1164 617.5 L1164 648.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path>
<path d="M326.5 423.5 L494.5 423.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="1032.5" y="639" style="font-weight:normal;">image_convert</text>
<text x="334.5" y="445" style="font-weight:normal;">...</text> <path d="M1024.5 648.5 L1487.5 648.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<rect x="330.5" y="494.5" height="62" width="159" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <rect x="1037.5" y="661.5" height="62" width="159" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<text x="338.8" y="516" style="">+ ProtocolError</text> <text x="1117" y="683" style="text-anchor: middle;">+ ConvertConfig</text>
<path d="M330.5 525.5 L489.5 525.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M1037.5 692.5 L1196.5 692.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="338.5" y="547" style="font-weight:normal;">...</text> <text x="1045.5" y="714" style="font-weight:normal;">...</text>
<rect x="297.5" y="596.5" height="62" width="225" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <path d="M1024.5 736.5 L1487.5 736.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="305.5" y="618" style="">+ ReplaceTextureStatus</text> <text x="1032.5" y="758" style="font-weight:normal;">+ generate_preview(input, format, config) : ...</text>
<path d="M297.5 627.5 L522.5 627.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <rect x="777.5" y="436.5" height="62" width="121" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<text x="305.5" y="649" style="font-weight:normal;">...</text> <text x="838" y="458" style="text-anchor: middle;">+ DataStore</text>
<path d="M53.5 786.5 L548.5 786.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M777.5 467.5 L898.5 467.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="61.5" y="808" style="font-weight:normal;">+ listen_forever(handler : &amp;ProtocolHandler) : ...</text> <text x="785.5" y="489" style="font-weight:normal;">...</text>
<rect x="161.5" y="44.5" height="220" width="280" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect> <rect x="938.5" y="387.5" height="190" width="223" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<path d="M161.5 44.5 L161.5 13.5 L215.5 13.5 L215.5 44.5 Z" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></path> <path d="M938.5 387.5 L938.5 356.5 L1011.5 356.5 L1011.5 387.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path>
<text x="169.5" y="35" style="font-weight:normal;">main</text> <text x="946.5" y="378" style="font-weight:normal;">result</text>
<path d="M161.5 44.5 L441.5 44.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M938.5 387.5 L1161.5 387.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M301.5 119.5 L301.5 139.5 L301.5 159.5 L301.5 159.5 " style="stroke:#33322E;fill:none;stroke-dasharray:6 6;"></path> <rect x="951.5" y="400.5" height="62" width="197" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<rect x="241.5" y="57.5" height="62" width="121" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect> <text x="1050" y="422" style="text-anchor: middle;">+ TextureFileResult</text>
<text x="249.8" y="79" style="">ServerState</text> <path d="M951.5 431.5 L1148.5 431.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<path d="M241.5 88.5 L362.5 88.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <text x="959.5" y="453" style="font-weight:normal;">...</text>
<text x="249.5" y="110" style="font-weight:normal;">...</text> <rect x="956.5" y="502.5" height="62" width="187" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<path d="M174.5 159.5 L420.5 159.5 L428.5 167.5 L428.5 220.5 L174.5 220.5 L174.5 159.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path> <text x="1050" y="524" style="text-anchor: middle;">+ TextureFileError</text>
<path d="M420.5 159.5 L420.5 167.5 L428.5 167.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M956.5 533.5 L1143.5 533.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="182.5" y="196" style="font-weight:normal;">implements</text> <text x="964.5" y="555" style="font-weight:normal;">...</text>
<text x="182.5" y="211" style="font-weight:normal;">protocol::ProtocolHandler</text> <rect x="1201.5" y="438.5" height="88" width="109" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></rect>
<path d="M161.5 233.5 L441.5 233.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path> <path d="M1201.5 438.5 L1201.5 407.5 L1274.5 407.5 L1274.5 438.5 Z" style="stroke:#33322E;fill:#fdf6e3;stroke-dasharray:none;"></path>
<text x="169.5" y="255" style="font-weight:normal;">+ main()</text></svg> <text x="1209.5" y="429" style="font-weight:normal;">search</text>
<path d="M1201.5 438.5 L1310.5 438.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<rect x="1214.5" y="451.5" height="62" width="83" style="stroke:#33322E;fill:#eee8d5;stroke-dasharray:none;"></rect>
<text x="1256" y="473" style="text-anchor: middle;">+ Query</text>
<path d="M1214.5 482.5 L1297.5 482.5" style="stroke:#33322E;fill:none;stroke-dasharray:none;"></path>
<text x="1222.5" y="504" style="font-weight:normal;">...</text></svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -41,6 +41,11 @@
[+ ProtocolConfig|...] [+ ProtocolConfig|...]
[+ ProtocolHandler] -/- [+ ProtocolConfig] [+ ProtocolHandler] -/- [+ ProtocolConfig]
[<package> autoconnect |
+ start_autoconnect_server(cfg : ProtocolConfig)
]
[result] -/- [autoconnect]
[<package> result| [<package> result|
[+ ProtocolResult|...] [+ ProtocolResult|...]
@ -56,8 +61,8 @@
[<package> main| [<package> main|
[ServerState|...] -- [<note> [ServerState|...]
implements [ServerState] -- [<note> implements
protocol::ProtocolHandler protocol::ProtocolHandler
] ]
| |
@ -70,4 +75,3 @@
[protocol] --> [model] [protocol] --> [model]
[persistency] --> [model] [persistency] --> [model]

View File

@ -0,0 +1,15 @@
- herunterladen (Release Gitea)
- installiern (Java VM)
- starten
- connecten
- neue textur einfügen
- query mit Tags
- query mit Name
- query mit Auflösung
- query mit Datum
- query mit Kombination
- exportieren
- ändern
- löschen
- settings file löschen

View File

@ -0,0 +1,7 @@
- herunterladen (Release Gitea)
- installiern (service daemon)
- starten
- loggen
- stoppen
- backups machen
- backups wieder einspielen

View File

@ -0,0 +1 @@
<mxfile modified="2019-06-18T13:37:07.094Z" host="www.draw.io" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36" etag="_ZMFen25GhU1ZPReOHi7" version="10.7.7" type="device"><diagram name="Page-1" id="10a91c8b-09ff-31b1-d368-03940ed4cc9e">7ZxZd+I2FMc/DY/p8Y55zDqd00nPnEmXyaOw5SUIy5XlAPn0lbC8YZihAVtyCnmIdSUbWf+fpcvVhYl5u1x/IiCNHrEP0cTQ/PXEvJsYhm7OLPaPWzaFxXFnhSEksS8a1Yan+A0KoyaseezDrNWQYoxonLaNHk4S6NGWDRCCV+1mAUbtd01BCDuGJw+grvXv2KeRsOqaVlf8CuMwEm/t2qJiDrxFSHCeiPebGGawfRXVS1BeS7TPIuDjVcNk3k/MW4IxLY6W61uI+NiWw1ac93Cgtuo3gQk95oQXNJ9Dffroxes5RvZv1w/foit+wrZzdFMOCPTZ+IgiJjTCIU4Auq+tN7X1C8Ypa6Yz4wukdCPkBTnFzBTRJRK1cB3T7+xYE8fP/PgXW5Tu1o2qu01ZSCjZfC8vwAuNs3ixPm1bKs97yZdpeQMJTniPPbyMPVHt5eQV+uKyxd3zWz44qsKU4Zx4opVjuDNTd11PC8DUdIyrElxAQkh/NNyV7ux5gngJWb/ZeQQiQOPXdh+AADus2tXisgOh73/R2nyH1q3Rag7jnlFWnIuBtTalam1dtB5Qa0uq1vZF6wG1tqVq7XwMrQfWTJepmamyZpVOz42anzyfjUfyufVEKvF8Tk/UenvqNSFg02iQ4jihWePKX7mBNViXvRXOlfgUpGt22xnfbe9oP2rPDooe1NRVt3ICiFOVQTSOJ3Fgolyps4errmj6RN0ZXxtItEM9fAUoF+8yMRzE+noT4O0UUCvp/JPjsuIq2472NWtg2em6rmRHIf9/TSgMwILC8nKsZ8UVi/oOJqsopvApBduxXBGQtkXchi62kHB5qugEr0JgDtFNFd+4xQiTGpiMEryApXFimL4zd2ynqinDKPxKQYxQo2UQBIbniTt+AMsYcTz+gsQHCRBmQZ3O1LsBKA4TVvAYI5BUN7kHmlfIhmfdMHWlF7XmrD31lvGZVR39sRzhUkeNwE85Y5/9CT8dGN3ZB8xtBAgftXPjop+Ii+O5cB4cg4sPoBucjkuHjT0EHcSl4qNcqc0uL3rZZhBejJ54+QIyCpMIBlQ5ZFxjbjpHzTC+DV3fUgsZQ5ONjNkTMl8DFHuRqtT409lc045bl6BzhnXpvNRMZVNj9UTNtziLF5iNLNpk5/dmTqVm7tqWfRw1rgdVo8a0ZFNj9zXXEPwCFzRFIFGOmZkzNcFR6xPU2Qo1VYsZS5fNjNMTM4/cpWEjlamJzbgWKNdRzq0xOtopExt5185HVehz5+Nw1PSYuMqp4dXTBP9oW9gjENyRKvhH28cegeByw90fbTN7BILPZAo+7cn1e4Ax89Iy7gapFi93tq+j3D6b/x3v9vFy4/Ti1ZM76GiqBUbdnlD6RPC8J5T+X8EKa3eXXDoy5uyy3JxpuSmDCD9db6Q6lJZ+EXxowXWp6ZHWJUgwvOJSk5+tS5RgeMWlpsValzDB8IobMhUvu3l2Z/8PmPFEz8tHxj52EGxbMf9fNw5ilNaqn4Or68UbTClI3vhu1EG+KnN6+Wx52u6U5Upn63DWTYettuK9APiZjXVI2NSMk2w0DI4rV3CXQfnJGPrhHJ73MTgAqI/Yz9FoCB1X6kdnD196kpl+OF9IWUKfNmwGXY4G0XFlz3YWcunZSXpf6Ul3gMIEkgggmiehcpsL4+Jmdz9KfnqSfoa9zb1fBfod0rcVJIuUYIoXmPdEMXTGldnWQUf+qtjXXuZT7kXq5VyPy83fxUUBN392Oi7Tfbj8+Vk5VsblcO+y0qc3w4r1z0kVXxqvf7PLvP8X</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,34 @@
- kleine Präsentation über Projekt
- Idee (Problem der Verwaltung vieler Texturen)
- Ziele (einfach, lokale Daten, gemeinschafftlicher Zugriff)
- Gelerntes (gute Planung, Tests, Versionsverwaltung, Issue-Tracker)
Jede Gruppe hat 20 Min für eine Präsentation des Projektes:
Welche waren die Ziele im Project Charter und was wurde erreicht
Kurze Präsentation der Artefakte (Lastenheft, Pflichtenheft, Grobdesign, System und Akzeptanztests, Traceability)
Welche Technologien wurden benutzt und warum
Welche Lehren zieht man / best practices für Projekt 2
Kurze Demo des Endproduktes
############ Traceability ############
Lastenheft F#1
Pflichtenheft MK#7
Grobdesign 2.2 View --> Import
Systemtest ST#1 bis ST#6
Akzeptanztests AT#1
TODO (Hendrik)
Planung ist alles
Aufgabenpakete (abhängig, parallel)
Fehler sofort dokumentieren und beheben
Issue Tracker
Versionsverwaltung
Tests
Wenn es geht nichts neues probieren, bewährtes beibehalten
In Endnutzer hineinversetzten

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,9 @@
<phases/> <phases/>
<calendars> <calendars>
<day-types> <day-types>
<day-type id="0" name="Working" description="A default working day"/> <day-type id="0" name="Arbeiten" description="Ein Vorgabe-Arbeitstag"/>
<day-type id="1" name="Nonworking" description="A default non working day"/> <day-type id="1" name="Nicht Arbeiten" description="Ein Vorgabetag, an dem nicht gearbeitet wird"/>
<day-type id="2" name="Use base" description="Use day from base calendar"/> <day-type id="2" name="Basis verwenden" description="Tag vom Basiskalender verwenden"/>
</day-types> </day-types>
<calendar id="1" name="Vorgabe"> <calendar id="1" name="Vorgabe">
<default-week mon="1" tue="0" wed="0" thu="1" fri="1" sat="0" sun="1"/> <default-week mon="1" tue="0" wed="0" thu="1" fri="1" sat="0" sun="1"/>
@ -16,7 +16,9 @@
<interval start="1300" end="1700"/> <interval start="1300" end="1700"/>
</overridden-day-type> </overridden-day-type>
</overridden-day-types> </overridden-day-types>
<days/> <days>
<day date="20190613" type="day-type" id="0"/>
</days>
</calendar> </calendar>
</calendars> </calendars>
<tasks> <tasks>
@ -92,88 +94,82 @@
<predecessor id="1" predecessor-id="10" type="FS"/> <predecessor id="1" predecessor-id="10" type="FS"/>
</predecessors> </predecessors>
</task> </task>
<task id="19" name="Realisation" note="" work="1065600" start="20190423T000000Z" end="20190511T170000Z" work-start="20190423T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="19" name="Realisation" note="" work="1641600" start="20190416T133640Z" end="20190612T170000Z" work-start="20190416T133640Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="18" type="FS"/> <predecessor id="1" predecessor-id="18" type="FS"/>
</predecessors> </predecessors>
<task id="20" name="Einrichtung von Tests" note="" work="28800" start="20190423T000000Z" end="20190423T170000Z" work-start="20190423T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="20" name="Einrichtung von Tests" note="" work="28800" start="20190416T133640Z" end="20190417T133640Z" work-start="20190416T133640Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="11" type="FS"/> <predecessor id="1" predecessor-id="11" type="FS"/>
</predecessors> </predecessors>
<task id="21" name="Client Tests" note="" work="28800" start="20190423T000000Z" end="20190423T170000Z" work-start="20190423T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> </task>
<task id="21" name="Client" note="" work="1123200" start="20190416T133640Z" end="20190612T170000Z" work-start="20190416T133640Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors>
<predecessor id="1" predecessor-id="11" type="FS"/>
</predecessors>
<task id="22" name="UI" note="" work="288000" start="20190416T133640Z" end="20190423T133640Z" work-start="20190416T133640Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<task id="23" name="Previews" note="" work="86400" start="20190416T133640Z" end="20190423T133640Z" work-start="20190416T133640Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"/>
<task id="24" name="Filter UI" note="" work="86400" start="20190416T133640Z" end="20190423T133640Z" work-start="20190416T133640Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"/>
<task id="25" name="3D Visualisierung" note="" work="57600" start="20190416T133640Z" end="20190420T133640Z" work-start="20190416T133640Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"/>
<task id="26" name="Dateien hinzuf&#xFC;gen" note="" work="28800" start="20190416T133640Z" end="20190417T133640Z" work-start="20190416T133640Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"/>
<task id="27" name="Dateien lokal abspeichern" note="" work="28800" start="20190416T133640Z" end="20190417T133640Z" work-start="20190416T133640Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"/>
</task>
<task id="28" name="Grund Architektur" note="" work="662400" start="20190423T000000Z" end="20190612T170000Z" work-start="20190423T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<constraint type="start-no-earlier-than" time="20190423T000000Z"/>
</task>
<task id="29" name="Protokoll implementieren" note="" work="172800" start="20190423T000000Z" end="20190504T170000Z" work-start="20190423T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<constraint type="start-no-earlier-than" time="20190423T000000Z"/> <constraint type="start-no-earlier-than" time="20190423T000000Z"/>
</task> </task>
</task> </task>
<task id="22" name="Client" note="" work="547200" start="20190423T000000Z" end="20190504T170000Z" work-start="20190423T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="30" name="Server" note="" work="489600" start="20190423T000000Z" end="20190511T170000Z" work-start="20190423T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="11" type="FS"/> <predecessor id="1" predecessor-id="11" type="FS"/>
</predecessors> </predecessors>
<task id="23" name="UI" note="" work="288000" start="20190423T170000Z" end="20190430T170000Z" work-start="20190424T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="31" name="Dateien speichern/verwalten" note="" work="172800" start="20190423T000000Z" end="20190504T170000Z" work-start="20190423T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<predecessors>
<predecessor id="1" predecessor-id="21" type="FS"/>
</predecessors>
<task id="24" name="Previews" note="" work="86400" start="20190423T170000Z" end="20190430T170000Z" work-start="20190424T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
<task id="25" name="Filter UI" note="" work="86400" start="20190423T170000Z" end="20190430T170000Z" work-start="20190424T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
<task id="26" name="3D Visualisierung" note="" work="57600" start="20190423T170000Z" end="20190427T170000Z" work-start="20190424T080000Z" percent-complete="50" priority="0" type="normal" scheduling="fixed-work"/>
<task id="27" name="Dateien hinzuf&#xFC;gen" note="" work="28800" start="20190423T170000Z" end="20190424T170000Z" work-start="20190424T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
<task id="28" name="Dateien lokal abspeichern" note="" work="28800" start="20190423T170000Z" end="20190424T170000Z" work-start="20190424T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"/>
</task>
<task id="29" name="Grund Architektur" note="" work="86400" start="20190423T000000Z" end="20190427T170000Z" work-start="20190423T080000Z" percent-complete="70" priority="0" type="normal" scheduling="fixed-work">
<constraint type="start-no-earlier-than" time="20190423T000000Z"/>
</task>
<task id="30" name="Protokoll implementieren" note="" work="172800" start="20190423T000000Z" end="20190504T170000Z" work-start="20190423T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<constraint type="start-no-earlier-than" time="20190423T000000Z"/>
</task>
</task>
<task id="31" name="Server" note="" work="489600" start="20190423T000000Z" end="20190511T170000Z" work-start="20190423T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors>
<predecessor id="1" predecessor-id="11" type="FS"/>
</predecessors>
<task id="32" name="Dateien speichern/verwalten" note="" work="172800" start="20190423T000000Z" end="20190504T170000Z" work-start="20190423T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<constraint type="must-start-on" time="20190423T000000Z"/> <constraint type="must-start-on" time="20190423T000000Z"/>
</task> </task>
<task id="33" name="Protokoll implementieren" note="" work="172800" start="20190423T000000Z" end="20190504T170000Z" work-start="20190423T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"> <task id="32" name="Protokoll implementieren" note="" work="172800" start="20190423T000000Z" end="20190504T170000Z" work-start="20190423T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<constraint type="must-start-on" time="20190423T000000Z"/> <constraint type="must-start-on" time="20190423T000000Z"/>
</task> </task>
<task id="34" name="Suche implementieren" note="" work="86400" start="20190504T170000Z" end="20190511T170000Z" work-start="20190507T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"> <task id="33" name="Suche implementieren" note="" work="86400" start="20190504T170000Z" end="20190511T170000Z" work-start="20190507T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="32" type="FS"/> <predecessor id="1" predecessor-id="31" type="FS"/>
</predecessors> </predecessors>
</task> </task>
<task id="35" name="Hauptlogik implementieren" note="Haupts&#xE4;chlich Glue-Code&#10;&#10;" work="57600" start="20190504T170000Z" end="20190508T170000Z" work-start="20190507T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work"> <task id="34" name="Hauptlogik implementieren" note="Haupts&#xE4;chlich Glue-Code&#10;&#10;" work="57600" start="20190504T170000Z" end="20190508T170000Z" work-start="20190507T080000Z" percent-complete="100" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="33" type="FS"/>
<predecessor id="1" predecessor-id="32" type="FS"/> <predecessor id="1" predecessor-id="32" type="FS"/>
<predecessor id="1" predecessor-id="31" type="FS"/>
</predecessors> </predecessors>
</task> </task>
</task> </task>
</task> </task>
<task id="36" name="End of Implementation" note="" work="0" start="20190511T170000Z" end="20190511T170000Z" work-start="20190511T170000Z" percent-complete="0" priority="0" type="milestone" scheduling="fixed-work"> <task id="35" name="End of Implementation" note="" work="0" start="20190612T170000Z" end="20190612T170000Z" work-start="20190612T170000Z" percent-complete="0" priority="0" type="milestone" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="31" type="FS"/> <predecessor id="1" predecessor-id="30" type="FS"/>
<predecessor id="1" predecessor-id="22" type="FS"/> <predecessor id="1" predecessor-id="21" type="FS"/>
<predecessor id="1" predecessor-id="20" type="FS"/> <predecessor id="1" predecessor-id="20" type="FS"/>
</predecessors> </predecessors>
</task> </task>
<task id="37" name="Abnahme" note="" work="374400" start="20190511T170000Z" end="20190611T170000Z" work-start="20190514T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="36" name="Abnahme" note="" work="115200" start="20190612T170000Z" end="20190613T170000Z" work-start="20190613T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<task id="38" name="Modultests [M]" note="" work="115200" start="20190511T170000Z" end="20190521T170000Z" work-start="20190514T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="37" name="Modultests [M]" note="" work="28800" start="20190612T170000Z" end="20190613T170000Z" work-start="20190613T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="36" type="FS"/> <predecessor id="1" predecessor-id="35" type="FS"/>
</predecessors> </predecessors>
</task> </task>
<task id="39" name="Integrationstests [M]" note="" work="115200" start="20190521T170000Z" end="20190529T170000Z" work-start="20190522T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="38" name="Integrationstests [M]" note="" work="28800" start="20190612T170000Z" end="20190613T170000Z" work-start="20190613T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="38" type="FS"/> <predecessor id="1" predecessor-id="35" type="FS"/>
</predecessors> </predecessors>
</task> </task>
<task id="40" name="Systemtests [M]" note="" work="115200" start="20190529T170000Z" end="20190608T170000Z" work-start="20190601T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="39" name="Systemtests [M]" note="" work="28800" start="20190612T170000Z" end="20190613T170000Z" work-start="20190613T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="39" type="FS"/> <predecessor id="1" predecessor-id="35" type="FS"/>
</predecessors> </predecessors>
</task> </task>
<task id="41" name="Akzeptanztest [M]" note="" work="28800" start="20190608T170000Z" end="20190611T170000Z" work-start="20190611T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work"> <task id="40" name="Akzeptanztest [M]" note="" work="28800" start="20190612T170000Z" end="20190613T170000Z" work-start="20190613T080000Z" percent-complete="0" priority="0" type="normal" scheduling="fixed-work">
<predecessors> <predecessors>
<predecessor id="1" predecessor-id="40" type="FS"/> <predecessor id="1" predecessor-id="35" type="FS"/>
</predecessors> </predecessors>
</task> </task>
</task> </task>
@ -186,16 +182,17 @@
<resource id="4" name="Lukas" short-name="L" type="1" units="0" email="" note="" std-rate="0"/> <resource id="4" name="Lukas" short-name="L" type="1" units="0" email="" note="" std-rate="0"/>
</resources> </resources>
<allocations> <allocations>
<allocation task-id="33" resource-id="1" units="100"/> <allocation task-id="29" resource-id="1" units="100"/>
<allocation task-id="32" resource-id="1" units="100"/>
<allocation task-id="8" resource-id="1" units="100"/> <allocation task-id="8" resource-id="1" units="100"/>
<allocation task-id="13" resource-id="1" units="100"/> <allocation task-id="13" resource-id="1" units="100"/>
<allocation task-id="11" resource-id="1" units="100"/> <allocation task-id="11" resource-id="1" units="100"/>
<allocation task-id="5" resource-id="1" units="50"/> <allocation task-id="5" resource-id="1" units="50"/>
<allocation task-id="29" resource-id="2" units="50"/> <allocation task-id="28" resource-id="2" units="50"/>
<allocation task-id="8" resource-id="2" units="10"/> <allocation task-id="8" resource-id="2" units="10"/>
<allocation task-id="17" resource-id="2" units="100"/> <allocation task-id="17" resource-id="2" units="100"/>
<allocation task-id="5" resource-id="2" units="50"/> <allocation task-id="5" resource-id="2" units="50"/>
<allocation task-id="29" resource-id="3" units="50"/> <allocation task-id="28" resource-id="3" units="50"/>
<allocation task-id="15" resource-id="3" units="100"/> <allocation task-id="15" resource-id="3" units="100"/>
<allocation task-id="12" resource-id="3" units="100"/> <allocation task-id="12" resource-id="3" units="100"/>
<allocation task-id="10" resource-id="3" units="100"/> <allocation task-id="10" resource-id="3" units="100"/>

View File

@ -0,0 +1,42 @@
#Statusbericht KW24 - TextureSync
Sehr geehrter Herr Nikolaropoulos,
hier der Statusbericht der vergangenen Woche TextureSync.
#Vergangene Arbeitswoche
* Der Client wurde fertiggestellt und um mehrere Wunschfunktionen ergänzt.
* Es wurden zwei Releases erstellt und getestet.
* Es wurden Kurzanleitungen für Server und Client erstellt.
#Nächste Arbeitswoche
* Die Präsentation für den 21.06.2019 fertigstellen.
#Aktuelle Informationen über das Projekt
Die Release 1.0.1 ist unsere erste Stable Release.
Alle Dokumente sind auf Moodle hochgeladen und somit von uns offiziell abgegeben.
Sie können sich gerne unsere Kurzanleitungen anschauen um einen ersten Eindruck der Software zu bekommen:
https://git.mosad.xyz/localhorst/TextureSync/wiki
Die eingebetteteten YouTube-Clips sind unsere Demos.
* Website mit aktuellem Projektplan: https://planner.mosad.xyz/TextureSync.html
* Repository mit Code und Dokumenten: https://git.mosad.xyz/localhorst/TextureSync
Sollten Sie Fragen haben, können Sie sich gern bei uns melden.
Wir freuen uns auf nächste Woche Freitag um Ihnen die fertige Software präsentieren zu können.
Mit freundlichen Grüßen
Hendrik Schutter und Team TextureSync

View File

@ -1,6 +1,6 @@
[package] [package]
name = "texture-sync-server" name = "texture-sync-server"
version = "0.1.0" version = "1.0.2"
authors = ["CodeSteak <codesteak@shellf.art>"] authors = ["CodeSteak <codesteak@shellf.art>"]
edition = "2018" edition = "2018"
@ -10,4 +10,4 @@ serde = { version = "1.0.90", features = ["derive"] }
serde_json = "1.0.39" serde_json = "1.0.39"
sha2 = "0.8.0" sha2 = "0.8.0"
lovecraft = "0.2.0" lovecraft = "0.2.0"
num_cpus = "1.0" num_cpus = "1.0"

View File

@ -24,6 +24,8 @@ use std::path::*;
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
lovecraft::invoke(); lovecraft::invoke();
println!("\n\n\t=== TextureSync Server {} ===\t\n\n\n", env!("CARGO_PKG_VERSION"));
let data_path = Path::new("./data"); let data_path = Path::new("./data");
println!("loading files from {:?}", data_path); println!("loading files from {:?}", data_path);
let server_state = ServerState::new(data_path)?; let server_state = ServerState::new(data_path)?;

View File

@ -69,7 +69,7 @@ impl Default for ProtocolConfig {
fn default() -> ProtocolConfig { fn default() -> ProtocolConfig {
ProtocolConfig { ProtocolConfig {
port: 10796, port: 10796,
read_timeout_s: 60, read_timeout_s: 3 * 600, // 30 Min.
write_timeout_s: 75, write_timeout_s: 75,
listen_addr: "::".to_owned(), listen_addr: "::".to_owned(),
autoconnect_multicastv6_addr: "ff02::dd42:c0fe".to_owned(), autoconnect_multicastv6_addr: "ff02::dd42:c0fe".to_owned(),

View File

@ -66,7 +66,7 @@ impl QueryFilter {
SpecialInName(name) => Score::RequiredMatch( SpecialInName(name) => Score::RequiredMatch(
// //
texture.name.contains(name), texture.name.to_lowercase().contains(&name.to_lowercase()),
), ),
SpecialBeforeDate(date) => Score::RequiredMatch(texture.added_on <= *date), SpecialBeforeDate(date) => Score::RequiredMatch(texture.added_on <= *date),

2
testdata/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
bin
outputdir

22
testdata/create.sh vendored Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
# use the correct working directory
cd $(dirname "$0")
# compile java code
mkdir -p bin
javac -sourcepath src -d bin src/creation/Creator.java
# recreate output dir
rm -rf outputdir
mkdir -p outputdir/data/textures
# create textures
java -classpath bin creation.Creator
# place a server binary in the output directory
(
cd ../server/texture-sync-server
cargo build --release
)
cp ../server/texture-sync-server/target/release/texture-sync-server ./outputdir/

184
testdata/src/creation/Creator.java vendored Normal file
View File

@ -0,0 +1,184 @@
package creation;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import java.util.UUID;
import javax.imageio.ImageIO;
public class Creator {
public static void main(String[] args) {
Random r = new Random(1);
String basedir = "outputdir/data";
String[] names = NameCreator.generateNames(r);
try {
FileOutputStream collectionOutput = new FileOutputStream(basedir + "/collection.json");
PrintWriter collectionWriter = new PrintWriter(collectionOutput);
collectionWriter.write("{\n \"textures\": [\n ");
boolean first = true;
int i=1;
for (String name : names) {
if (first) {
first = false;
} else {
collectionWriter.write(",\n ");
}
System.out.println("Creating " + name + " (texture " + i + " of " + names.length + ")");
storeImage(name, basedir, r, collectionWriter);
i++;
}
collectionWriter.write("\n ]\n}\n");
collectionWriter.close();
collectionOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static boolean randBool(Random r, double probability) {
return r.nextDouble() < probability;
}
private static void storeImage(String name, String outputdir, Random r, PrintWriter collectionWriter)
throws IOException {
int size = 256 * (1 << r.nextInt(6));
NamedColor[] shuffling = Dictionary.colors.clone();
NamedColor[] mycolors = new NamedColor[3];
for (int i = 0; i < 3; i++) {
int otherPos = r.nextInt(7 - i) + i;
mycolors[i] = shuffling[otherPos];
shuffling[otherPos] = shuffling[i];
}
MyDate date = randomDate(r);
boolean grey = randBool(r, 0.01);
boolean border = randBool(r, 0.1);
boolean bold = randBool(r, 0.03);
boolean italic = randBool(r, 0.07);
BufferedImage img = createImage(size, name, mycolors, date, grey, border, bold, italic);
File tmpLocation = new File(outputdir + "/tempimage");
ImageIO.write(img, name.substring(name.length() - 3), tmpLocation);
String hash = hashFile(tmpLocation);
String ending = name.substring(name.length() - 3);
if (ending.equals("jpg")) {
ending = "jpeg";
}
tmpLocation.renameTo(new File(outputdir + "/textures/" + hash));
String tags = mycolors[0].name + "\", \"" + mycolors[1].name + "\", \"" + mycolors[2].name;
if (grey) {
tags += "\", \"grey";
}
if (border) {
tags += "\", \"border";
}
if (bold) {
tags += "\", \"bold";
}
if (italic) {
tags += "\", \"italic";
}
collectionWriter.write("{\n");
collectionWriter.write(" \"id\": \"" + UUID.randomUUID() + "\",\n");
collectionWriter.write(" \"name\": \"" + name + "\",\n");
collectionWriter.write(" \"tags\": [\"" + tags + "\"],\n");
collectionWriter.write(" \"format\": \"" + ending + "\",\n");
collectionWriter.write(" \"resolution\": [" + size + ", " + size + "],\n");
collectionWriter.write(" \"added_on\": " + date.asJsonArray() + ",\n");
collectionWriter.write(" \"texture_hash\": \"" + hash + "\"\n");
collectionWriter.write(" }");
}
private static MyDate randomDate(Random r) {
int back = (int) (-300 * Math.log(r.nextDouble()));
return new MyDate(3, 6, 2019).ago(back);
}
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
private static String hashFile(File f) throws IOException {
byte[] data = Files.readAllBytes(f.toPath());
try {
MessageDigest hash = MessageDigest.getInstance("SHA-256");
byte[] hashval = hash.digest(data);
return bytesToHex(hashval);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
private static BufferedImage createImage(int size, String name, NamedColor[] colors, MyDate date, boolean grey,
boolean border, boolean bold, boolean italic) {
BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
// background
if (grey) {
g.setColor(Color.LIGHT_GRAY);
} else {
g.setColor(Color.WHITE);
}
g.fillRect(0, 0, size, size);
// border
if (border) {
int w = size / 40;
int l = size - 2*w;
g.setColor(Color.BLACK);
g.fillRect(w, w, l, w);
g.fillRect(w, w, w, l);
g.fillRect(w, l, l, w);
g.fillRect(l, w, w, l);
}
// text
int fontstyle = Font.PLAIN;
if (bold) {
fontstyle |= Font.BOLD;
}
if (italic) {
fontstyle |= Font.ITALIC;
}
Font f = new Font("Arial", fontstyle, size / 10);
g.setFont(f);
g.setColor(Color.BLACK);
int width = g.getFontMetrics().stringWidth(name);
int basey = size / 2 + g.getFontMetrics().getAscent();
int textheight = g.getFontMetrics().getHeight();
g.drawString(name, (size - width) / 2, basey);
g.drawString(size + " x " + size, (size - width) / 2, basey + textheight);
g.drawString(date.asReadableString(), (size - width) / 2, basey + 2 * textheight);
// color dots
for (int i = 0; i < 3; i++) {
NamedColor current = colors[i];
g.setColor(current.color);
g.fillOval((1 + 3 * i) * size / 10, size * 3 / 10, size / 5, size / 5);
}
return img;
}
}

16
testdata/src/creation/Dictionary.java vendored Normal file
View File

@ -0,0 +1,16 @@
package creation;
import java.awt.Color;
public class Dictionary {
public static final String[] adjectives = { "fast", "slow", "long", "short", "fat", "big", "small", "angry",
"awful", "calm", "clever", "crazy", "dirty", "excited", "evil", "kind", "lucky", "poor", "shy", "soft",
"tall", };
public static final String[] animals = { "bat", "bee", "camel", "cat", "chicken", "cod", "deer", "dog", "duck",
"fly", "fox", "frog", "horse", "koala", "lion", "mouse", "owl", "pig", "rabbit", "rat", "tiger", "turtle",
"wolf", "zebra" };
public static final NamedColor[] colors = { new NamedColor("red", Color.RED),
new NamedColor("orange", Color.ORANGE), new NamedColor("yellow", Color.YELLOW),
new NamedColor("green", Color.GREEN), new NamedColor("blue", Color.BLUE),
new NamedColor("magenta", Color.MAGENTA), new NamedColor("black", Color.BLACK), };
}

66
testdata/src/creation/MyDate.java vendored Normal file
View File

@ -0,0 +1,66 @@
package creation;
public class MyDate {
public final int day, month, year;
public MyDate(int day, int month, int year) {
if (!isValid(day, month, year)) {
throw new IllegalArgumentException("Invalid date");
}
this.day = day;
this.month = month;
this.year = year;
}
public String asJsonArray() {
return "[" + year + ", " + month + ", " + day + "]";
}
public String asReadableString() {
return twoDigit(day) + "." + twoDigit(month) + "." + twoDigit(year);
}
public MyDate previous() {
if (isValid(day - 1, month, year)) {
return new MyDate(day - 1, month, year);
}
for (int possibleDay = 31; possibleDay >= 28; possibleDay--) {
if (isValid(possibleDay, month - 1, year)) {
return new MyDate(possibleDay, month - 1, year);
}
}
return new MyDate(31, 12, year - 1);
}
public MyDate ago(int number) {
MyDate d = this;
for (int i=0; i<number; i++) {
d = d.previous();
}
return d;
}
private static String twoDigit(int x) {
String s = ""+x;
while (s.length() < 2) {
s = "0"+s;
}
return s;
}
private boolean isValid(int day, int month, int year) {
int[] monthLengths = new int[] { 31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month < 1 || month > 12) {
return false;
}
int length = monthLengths[month - 1];
if (day < 1 || day > length) {
return false;
}
return true;
}
private boolean isLeapYear(int year) {
return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
}
}

35
testdata/src/creation/NameCreator.java vendored Normal file
View File

@ -0,0 +1,35 @@
package creation;
import java.util.ArrayList;
import java.util.Random;
public class NameCreator {
private static void shuffle(ArrayList<String> list, Random r) {
for (int low=0; low<list.size()-1; low++) {
int high = r.nextInt(list.size() - low) + low;
// swap
String sLow = list.get(low);
String sHigh = list.get(high);
list.set(low, sHigh);
list.set(high, sLow);
}
}
public static String[] generateNames(Random r) {
ArrayList<String> names = new ArrayList<>();
for (String ending : new String[] {"jpg", "png"}) {
for (String animal : Dictionary.animals) {
for (String adjective : Dictionary.adjectives) {
String name = adjective + "-" + animal + "." + ending;
names.add(name);
}
}
}
shuffle(names, r);
while (names.size() > 1000) {
names.remove(names.size() - 1);
}
return names.toArray(new String[1000]);
}
}

13
testdata/src/creation/NamedColor.java vendored Normal file
View File

@ -0,0 +1,13 @@
package creation;
import java.awt.Color;
public class NamedColor {
public final String name;
public final Color color;
public NamedColor(String name, Color color) {
this.name = name;
this.color = color;
}
}