Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • heevtont/ohj2
  • ojmannex/ohj2
  • veosvuol/ohj2
  • teoilalo/ohj2
  • pakakata/ohj2
  • tie/ohj2/2023k/ohj2
  • jupesate/ohj2
  • olrutane/ohj2
  • vesal/ohj-2-k-23
  • alejarta/ohj2
  • romaasun/ohj2
  • maxvitik/ohj2
  • jatakarj/ohj2
  • forsheal/harjoitustyo
  • paemhiet/ohj2
  • onhuhtal/ohj2
  • peukteni/ohj2
  • kallvaxu/ohj-2-ht-kasityorekisteri
  • piipjuhe/ohj2
  • alanenee/ohj2
  • osterava/ohj2
  • savolpet/ohj2
  • jaalsiik/ohj2
  • jbpalola/ohj2
  • khakarpp/ohj2
  • sokapalo/ohj2
  • luomkohe/ohj2
  • ltahonex/ohj2
  • hejojurv/ohj-2-sukupuu
  • karkhkxy/ohj2
  • vewaheik/ohj2
  • tejumeri/ohj2
  • erkkjjyv/ohj2
  • kkautio/ohj2
  • jaeianro/ohj2
  • olmisalo/ohj2
  • ukkolaaa/ohj2
  • esbrunil/ohj2
  • pjsavola/ohj2
  • mosaluht/jasenrekisteri
  • nviianen/ohj2
  • eetpatsu/ohj2
  • iinelipi/ohj2
  • kaupkama/ohj2
  • myyryejk/ohj-2-ht-myyry
  • mnjtiili/ohj2
  • leppanm/ohj2
  • malineps/ohj2
  • antulepp/ohj-2-b
  • helatukk/ohj2
  • aaahalom/ohj2
  • juvonevi/ruokanaattori
  • atkaanhe/ohj2
  • jypemiko/ohj2-23
  • anuemiko/ohj2
  • lvvuolle/ohj2
  • valkeiti/ohj-2
  • suvileos/ohj2
  • mikpekpu/ohj2
  • savevalo/ohj2
  • martiksm/ohj2
  • enlejuhe/ohj2
  • eealhakk/ohj-2-ht
  • savomaaa/ohj2
  • elkrleht/ohj2
  • maospelt/ohj2
  • tufiras/ohj2
  • lihavavy/ohj2
  • pepihlaj/ohj2
  • urpiteju/ohj2
  • aetakala/ohj-2-ht
  • tjkajant/ohj2
  • remoneve/ohj2
  • jeismont/ohj2
  • mietanai/ohj2
  • inkilaka/ohj2
  • pmruusu/ohj2
  • pykakimp/reseptirekisteriprojekti
  • mielarju/ohj2
  • jmjleixu/ohj2
  • kalakoiv/ohj2
  • meamalxv/ohj2
  • heinota/ohj2
  • majauusi/ohj2
  • tusakki/ohj2
  • jjpahkin/ohj2
  • nurmimk/ohj2
  • mieemalo/ohj2
  • idmahako/ohj2
  • ajrautia/ohj2
  • evaltaiv/ohj2
  • vevajoki/ohj2
  • vijumato/ohj2
  • nikrantt/ohj2
  • kupialnx/ohj2
  • jujukest/ohj2ht
  • aojuntun/ohj2
  • jhthorxu/ohj2
  • aaaalto/ohj2
  • haggpoo/ohj2
  • mialniem/ohj2
  • marteevi/ohj2
  • amslappi/ohj2
  • jiheikzt/ohj2
  • elbeeltv/ohj2
  • virommss/ohj2
  • tootuoka/ohj2
  • hasultxt/ohj-2
  • laanmaat/ohj-2-2023
  • laueerjo/ohj2
  • jutakoir/osrsprocesspal
  • alalojap/ohj2
  • joaahirv/ohj2
  • venmaamo/ohj2
  • jejaolpa/ohj2
  • anbudano/ohj2
  • peolkyll/ohj2
  • blomerjo/ohj2
  • aasahonk/ohj2
  • lapahama/ohj2
  • karpot/ohj2
  • psbroman/ohj2
  • vemakael/ohj2
  • alninybe/harkkatyo
  • tosakorh/ohj-2-k-23
  • ntkumpul/ntkumpul
  • riiijoko/ohj-2-2023
127 results
Show changes
Showing
with 1218 additions and 0 deletions
package guru.kake.ronove
import javafx.beans.property.ReadOnlyObjectProperty
import javafx.beans.property.SimpleIntegerProperty
import javafx.scene.control.TableView
import tornadofx.App
import tornadofx.launch
import tornadofx.toProperty
/**
* Main class for the Ronove application
*/
class Ronove: App(MainView::class, RonoveStylesheet::class) {
/** Current project data */
var project = Project()
/** Property for listening to changes on selected table view cell */
var cellSelection: ReadOnlyObjectProperty<Line> = Line().toProperty()
/** Currently selected page */
var currentPage = SimpleIntegerProperty(1)
/** Amount of pages in project */
var pageCount = SimpleIntegerProperty(project.pages.size)
lateinit var table: TableView<Line>
/**
* Change current page
* @param page page to change to
*/
fun changePage(page: Int) {
currentPage.value = page
}
/**
* Add new page to the end
*/
fun addPage() {
project.pages.add(Page())
pageCount.set(project.pages.size)
table.refresh()
}
fun addLine() {
project.pages[currentPage.value-1].lines.add(Line())
table.refresh()
}
fun removePage() {
project.pages.removeAt(currentPage.value-1)
pageCount.set(project.pages.size)
table.refresh()
}
}
/** Program entry point */
fun main(args: Array<String>) = launch<Ronove>(args)
package guru.kake.ronove
import javafx.geometry.Pos
import tornadofx.*
/**
* Holds the CSS styles for the program
*/
class RonoveStylesheet: Stylesheet() {
companion object {
/** Centers alignment */
val vcenter by cssclass()
/** Increases font size of a label */
val bigLabel by cssclass()
}
init {
vcenter {
alignment = Pos.CENTER
}
bigLabel {
fontSize = 40.px
}
Stylesheet.tableView {
}
}
}
\ No newline at end of file
package guru.kake.ronove
import tornadofx.*
import kotlin.system.exitProcess
/**
* The splash screen show on program startup, allowing the user to create a new project or load an existing
* one
* @param project the Project object the data of a new empty project or the chosen loaded project will be
* stored into
*/
class SplashScreen(project: Project) : View("Ronove") {
/** TornadoFX root */
override val root = borderpane {
center = form {
fieldset {
field {
hyperlink("Dummy 1") {
action {
project.pages = mutableListOf(
Page(listOf(
Line("なんでタバコすってんだ?","Why are you smoking?","Why do you smoke?"),
Line("んー","Hmm.","Hmm..."),
Line("フー","whoosh","Haa...", "SFX: Exhaling"),
Line("カツコつけてんの","I'm trying to be cool.",
"I'm just trying to look cool"),
Line("かっこいー","That's so cool.", "Coooool!")
)),
Page(listOf(
Line("Sivu 2","Page 2","Page 2"),
Line("a","b","c"),Line("a","b","c"),
Line("a","b","c")
)),
Page(listOf(
Line("Sivu 3","Page 3","Page 3"),
Line("a","b","c"),Line("a","b","c"),Line("a","b","c"),Line("a","b","c"),
Line("a","b","c")
)),
Page(listOf(
Line("Sivu 4","Page 4","Page 4"),
Line("a","b","c"),Line("a","b","c"),
Line("a","b","c")
)),
Page(listOf(
Line("Sivu 5","Page 5","Page 5"),
Line("a","b","c"),
Line("a","b","c")
))
)
close()
(app as Ronove).table.refresh()
}
}
progressbar(0.2)
}
field {
hyperlink("Dummy 2")
progressbar(0.3)
}
field {
hyperlink("Dummy 3")
progressbar(0.5)
}
field {
hyperlink("Dummy 4")
progressbar(0.9)
}
field {
hyperlink("Dummy 5")
progressbar(0.9)
}
field {
button("New project") { action {
project.new()
(app as Ronove).table.refresh()
close()
}}
button("Open...") { action {
project.open()
(app as Ronove).table.refresh()
close()
}}
button("Exit") { action { exitProcess(0) }}
}
}
}
right = imageview("/ronove300.png") {
fitHeight = 200.0
isPreserveRatio = true
}
visibleProperty().onChange {
currentWindow?.sizeToScene()
}
}
override fun onDock() {
modalStage?.width = 450.0
}
}
\ No newline at end of file
package guru.kake.ronove
import com.deepl.api.DeepLException
import com.deepl.api.Translator
import com.google.cloud.translate.Translate
import com.google.cloud.translate.TranslateException
import com.google.cloud.translate.TranslateOptions
import com.google.cloud.translate.Translation
import javafx.beans.property.SimpleDoubleProperty
import javafx.beans.property.SimpleStringProperty
import tornadofx.getValue
import tornadofx.setValue
/**
* Provides access to different machine translation services through a unified interface
*/
class TranslationBackend {
companion object {
private var service: TranslationService? = null
var serviceName = SimpleStringProperty()
var quotaMax = 0L
var quotaUsed = 0L
val quotaProperty = SimpleDoubleProperty()
var quota by quotaProperty
var destinationLanguage: String = ""
var sourceLanguage: String = ""
/**
* Translate one string of text
* @param text Text to translate
* @param sourceLang Override source language, otherwise defaults to what is set
* in [TranslationBackend]
* @param destLang Override destination language, otherwise defaults to what is set
* in [TranslationBackend]
* @return Translated string
*/
operator fun invoke(
text: String, sourceLang: String = sourceLanguage, destLang: String = destinationLanguage)
: String = service?.translate(text, sourceLang, destLang) ?:
throw TranslationServiceUnitializedException("Translation service uninitialized!")
/**
* Translate a list of strings
* @param textList List to translate
* @param sourceLang Override source language, otherwise defaults to what is set
* in [TranslationBackend]
* @param destLang Override destination language, otherwise defaults to what is set
* in [TranslationBackend]
* @return List of translated strings
* @throws TranslationServiceUnitializedException When no translation service has been initialized
*/
operator fun invoke(
textList: List<String>, sourceLang: String = sourceLanguage, destLang: String = destinationLanguage)
: List<String> = service?.translate(textList, sourceLang, destLang) ?:
throw TranslationServiceUnitializedException("Translation service uninitialized!")
val provider: String = when (service) {
null -> "uninitialized"
is DeepLTranslator -> "DeepL"
else -> "error"
}
/**
* Sets the translation service to be used
* @param service Object implementing [TranslationService] interface
* @param name name of service
*/
fun setService(service: TranslationService, name: String) {
this.service = service
serviceName.value = name
}
}
}
/**
* Interface for machine translating strings and lists of strings
*/
interface TranslationService {
/**
* Translate a single String of text
*
* @param text Text to translate
* @param sourceLang Override source language, otherwise defaults to what is set in [TranslationBackend]
* @param destLang Override destination language, otherwise defaults to what is set
* in [TranslationBackend]
* @return Translated string
*/
fun translate(text: String, sourceLang: String, destLang: String): String
/**
* Translate multiple Strings of text.
*
* Default implementation calls the single string translate() repeatedly, if the backed supports a way to
* translate multiple strings in one request, override this function to do that instead.
*
* @param textList List to translate
* @param sourceLang Override source language, otherwise defaults to what is set in [TranslationBackend]
* @param destLang Override destination language, otherwise defaults to what is set
* in [TranslationBackend]
* @return List of translated strings
* @throws TranslationServiceUnitializedException When no translation service has been initialized
*/
fun translate(textList: List<String>, sourceLang: String, destLang: String): List<String> =
List(textList.size) {
translate(textList[it], sourceLang, destLang)
}
}
/**
* TranslationsService implementation using DeepL online translation
*
* @param[key] DeepL API key
* @throws[TranslationServiceException] wraps API-specific exceptions
*/
class DeepLTranslator(key: String) : TranslationService {
private var deepl: Translator
init {
try {
deepl = Translator(key)
val usage = deepl.usage
TranslationBackend.quotaUsed = usage.character!!.count
TranslationBackend.quotaMax = usage.character!!.limit
TranslationBackend.quota = usage.character!!.count.toDouble() / usage.character!!.limit
} catch (e: DeepLException) {
throw TranslationServiceException("Error: ${e.message}", e)
} catch (e: IllegalArgumentException) {
throw TranslationServiceException("API key must not be empty")
}
}
override fun translate(text: String, sourceLang: String, destLang: String): String {
try {
return deepl.translateText(text, sourceLang, destLang).text
} catch (e: DeepLException) {
throw TranslationServiceException("DeepL API translation failed with message: ${e.message}", e)
}
}
override fun translate(textList: List<String>, sourceLang: String, destLang: String): List<String> {
try {
val translations = deepl.translateText(textList, sourceLang, destLang)
return List<String>(translations.size) { translations[it].text }
} catch (e: DeepLException) {
throw TranslationServiceException("DeepL API translation failed with message: ${e.message}", e)
}
}
}
/**
* TranslationsService implementation using Google Translate online translation using the basic, free v2 API
*
* @param[key] Google Cloud Translate API key
* @throws[TranslationServiceException] wraps API-specific exceptions
*/
class GoogleTranslator(key: String) : TranslationService {
private val translate: Translate
init {
@Suppress("DEPRECATION")
translate = TranslateOptions.newBuilder().setApiKey(key).build().service
}
override fun translate(text: String, sourceLang: String, destLang: String): String {
try {
val translation: Translation = translate.translate(
text,
Translate.TranslateOption.sourceLanguage(sourceLang),
Translate.TranslateOption.targetLanguage(destLang)
)
return translation.translatedText
} catch (e: TranslateException) {
throw TranslationServiceException("Google API translation failed with message: ${e.message}", e)
}
}
override fun translate(textList: List<String>, sourceLang: String, destLang: String): List<String> {
try {
val translations: List<Translation> = translate.translate(
textList,
Translate.TranslateOption.sourceLanguage(sourceLang),
Translate.TranslateOption.targetLanguage(destLang)
)
return List<String>(translations.size) { translations[it].translatedText }
} catch (e: TranslateException) {
throw TranslationServiceException("Google API translation failed with message: ${e.message}", e)
}
}
}
/**
* Exception thrown when translation fails, usually due to errors accessing the online service providing
* translation.
*/
class TranslationServiceException(message: String? = null, cause: Throwable? = null) :
Exception(message, cause)
/** Exception thrown when trying to translate without a service set. */
class TranslationServiceUnitializedException(message: String? = null) : Exception(message)
\ No newline at end of file
package guru.kake.ronove
import javafx.scene.control.TableView
import tornadofx.*
/**
* The central view of the main window used to shew the table of the translation data
* @param ronove reference to the main app
*/
class TranslationPageView(val ronove: Ronove) : View() {
init {
PageJumpMenu.pageView = this
}
private lateinit var tableView: TableView<Line>
/** TornadoFX fragment for page chaning buttons */
lateinit var pageJumps: PageJumpMenu
/** TornadoFX root */
override val root = borderpane {
tableView = tableview {
isEditable = true
column("Original", Line::original).makeEditable()
column("Machine translation", Line::machineTranslation).makeEditable()
column("Final", Line::finalTranslation).makeEditable()
column("Notes", Line::notes).makeEditable()
contextmenu {}
}
ronove.table = tableView
tableView.selectionModel.isCellSelectionEnabled = true
/*tableView.selectionModel.selectedItemProperty().addListener(fun(_, _, newSelection) {
if (newSelection != null) {
val row: Int = tableView.selectionModel.selectedCells[0].row
val col = tableView.columns[tableView.selectionModel.selectedCells[0].column]
Platform.runLater { tableView.edit(row, col) }
}
})
tableView.onKeyPressed = EventHandler { event: KeyEvent ->
val pos: TablePosition<*, *>? = tableView.focusModel.focusedCell
if (pos != null && event.code.isLetterKey) {
@Suppress("UNCHECKED_CAST")
tableView.edit(pos.row, pos.tableColumn as TableColumn<Line, *>?)
}
}*/
center = tableView
pageJumps = PageJumpMenu()
bottom = pageJumps.root
}
init {ronove.cellSelection = tableView.selectionModel.selectedItemProperty()}
/**
* Loads the currently selected page to the table view
*/
private fun refresh() {
tableView.items =
ronove.project.pages[ronove.currentPage.value-1].lines.asObservable()
tableView.refresh()
}
init {
ronove.currentPage.addListener { _ -> refresh(); pageJumps.refresh()}
ronove.pageCount.addListener { _ -> pageJumps.refresh()}
}
}
/**
* Fragment of the main window implementing the page switcher at the bottom
*/
class PageJumpMenu : Fragment() {
companion object {
internal lateinit var pageView: TranslationPageView
}
/**
* Refresh the page switcher, updating the selected page and number of pages
*/
fun refresh() {
val menu = PageJumpMenu()
replaceWith(menu)
pageView.pageJumps = menu
}
/** TornadoFX root */
override val root = hbox {
addClass(RonoveStylesheet.vcenter)
button("<<") {action {pageView.ronove.changePage(1)}}
button("<") {action { pageView.ronove.changePage(pageView.ronove.currentPage.value-1)}}
for (i in 1..pageView.ronove.pageCount.get()) {
button("$i") {action {pageView.ronove.changePage(i)}}
}
menubutton("...") {
for (i in 1..pageView.ronove.pageCount.get()) {
item("$i") {action {pageView.ronove.changePage(i)}}
}
}
button(">") {action { pageView.ronove.changePage(pageView.ronove.currentPage.value+1)}}
button(">>") {action { pageView.ronove.changePage(pageView.ronove.pageCount.get())}}
button("+") {
action {
pageView.ronove.addPage()
}
}
}
}
\ No newline at end of file
package guru.kake.ronove
import javafx.beans.property.SimpleStringProperty
import javafx.scene.control.*
import javafx.scene.paint.Color
import tornadofx.*
/**
* Window for selecting MTL service provider and setting its API key
*/
class TranslationSettings(private val translationBackends: Map<String,
(String) -> TranslationService> = defaultBackends) : View("Settings") {
companion object {
/**
* The list of backends to show in the settings menu. Add a line here if you implement a new
* backend class.
*/
val defaultBackends = mapOf<String, (String) -> TranslationService>(
"DeepL" to {DeepLTranslator(it)},
"Google Translate API v2" to {GoogleTranslator(it)}
)
}
private lateinit var applyButton : Button
internal val toggleGroup = ToggleGroup()
private var backends: MutableList<MTLSettingsMenu<TranslationService>> = mutableListOf()
/** TornadoFX root */
override val root = form {
label {
text = "Be aware that use of translation APIs may incur costs in accordance to their usage " +
"terms. Check with the translation service provider for their rates. While Ronove will " +
"attempt to minimize API calls where appropriate, be aware that for some providers " +
"even testing the API key may be a billed operation."
isWrapText = true
prefWidth = 300.0
}
fun MTLSettingsMenu<*>.add() {
@Suppress("UNCHECKED_CAST")
backends.add(this as MTLSettingsMenu<TranslationService>)
this@form += this
}
for (p in translationBackends) {
MTLSettingsMenu(this@TranslationSettings, p.key) { p.value(it) }.add()
}
hbox {
applyButton = button("Apply") {
isDefaultButton = true
isDisable = true
action {
val backend = backends.find {it.radio == toggleGroup.selectedToggle}
TranslationBackend.setService(backend!!.service!!, backend.name)
close()
}
}
button("Cancel") {
isCancelButton = true
action {
close()
}
}
}
}
/**
* Validates the settings and enables the Apply button accordingly
*/
fun updateButton() {
applyButton.isDisable = backends.find { it.radio == toggleGroup.selectedToggle }?.service == null
if (!applyButton.isDisable) { applyButton.requestFocus() }
}
}
/**
* UI Fragment to implement a settings menu for a translation backend requiring one API key as string
*/
private class MTLSettingsMenu<T: TranslationService>(
private val parent: TranslationSettings, val name: String, val constructor: (String) -> T)
: Fragment(name) {
private lateinit var statusLabel: Label
private lateinit var keyField: PasswordField
private lateinit var saveButton: Button
lateinit var radio: RadioButton
var service: T? = null
private val key = SimpleStringProperty()
override val root = fieldset {
radio = radiobutton(name, this@MTLSettingsMenu.parent.toggleGroup) {
action { this@MTLSettingsMenu.parent.updateButton() }
addClass("radio")
}
field("API key") {
keyField = passwordfield(key) {
action { saveButtonAction() }
addClass("field")
}
}
saveButton = button("Save & test") {
action { saveButtonAction() }
}
statusLabel = label()
}
init {
key.value = ""
if (TranslationBackend.serviceName.value == name) {
key.value = "**********"
radio.isSelected = true
}
saveButton.isDisable = true
key.onChange { saveButton.isDisable = key.value == "" || key.value == "**********" }
}
private fun saveButtonAction() {
try {
service = constructor(keyField.text)
statusLabel.text = "API initialized succesfully!"
statusLabel.textFill = Color.GREEN
} catch (e: TranslationServiceException) {
statusLabel.text = e.message
statusLabel.textFill = Color.RED
} finally {
parent.updateButton()
}
}
}
\ No newline at end of file
package guru.kake.bst
/**
* Implementation for a binary search tree
* @param T Type of tree node contents. This should be a [Comparable] where [compareTo] defines the order of
* the tree.
* @param list list of nodes to initialize tree from
*/
class BST<T : Comparable<T>>(list: List<T>) {
private var root: Node<T>? = null
init {
val list2 = list.sorted()
root = Node(list2[list2.size/2])
createBST(list2, root!!)
}
private fun createBST(children: List<T>, parent: Node<T>) {
val left = children.subList(0, children.size / 2)
val right = children.subList(children.size / 2 + 1, children.size)
if (left.isNotEmpty()) {
parent.left = Node(left[left.size / 2])
createBST(left, parent.left!!)
}
if (right.isNotEmpty()) {
parent.right = Node(right[right.size / 2])
createBST(right, parent.right!!)
}
}
/**
* Find [value] from tree and return it if it exist, otherwise null is returned
* @param value
* @return matching [T] if found or null
*/
fun find(value: T): T? {
var node = root
while (true) {
if (node!=null) {
if (node.value < value) {
node = node.right
continue
}
else if (node.value > value) {
node = node.left
continue
}
}
return node?.value
}
}
/**
* Node of the binary search tree
* @param T contained type
* @param value content of the node
*/
class Node<T>(val value: T) {
/** Child node which compares to less than this */
var left: Node<T>? = null
/** Child node which compares to more than this */
var right: Node<T>? = null
}
}
\ No newline at end of file
package guru.kake.xmlp
import java.io.FileInputStream
import java.io.InputStream
import javax.xml.namespace.QName
import javax.xml.stream.XMLEventReader
import javax.xml.stream.XMLInputFactory
import javax.xml.stream.events.XMLEvent
/** DSL marker */
@DslMarker
annotation class DSL
/**
* Implements a DSL-language for event-based parsing of XML files.
*/
@DSL
class XMLParser private constructor(stream: InputStream) {
companion object {
/**
* Parse an XML-file using an event-based interface
* @param path path to file
* @param init lambda to execute on each XML event
*/
fun parse(path: String, init: XMLParser.() -> Unit): Unit =
XMLParser(FileInputStream(path)).init(init)
/**
* Parse an XML-file using an event-based interface
* @param stream [InputStream] containing XML data
* @param init lambda to execute on each XML event
*/
fun parse(stream: InputStream, init: XMLParser.() -> Unit): Unit = XMLParser(stream).init(init)
}
private val factory: XMLInputFactory = XMLInputFactory.newInstance()
private val reader: XMLEventReader = factory.createXMLEventReader(stream)
private val elements: MutableMap<String, Element> = mutableMapOf()
private fun init(init: XMLParser.() -> Unit) {
@Suppress("UNUSED_EXPRESSION") // IntelliJ IDEA bug: https://youtrack.jetbrains.com/issue/KT-21282
init()
while (reader.hasNext()) {
parse(reader.nextEvent())
}
}
private fun parse(event: XMLEvent) {
when {
event.isStartElement -> {
elements[event.asStartElement().name.localPart.toString()]?.parseStart(event)
}
event.isEndElement -> {
elements[event.asEndElement().name.localPart.toString()]?.parseEnd()
}
}
}
/**
* Specify code to execute based on element name
* @param name Element name
* @param f code to execute on elements matching name
*/
fun element(name: String, f: Element.() -> Unit) {
elements[name] = Element(reader).also { it.f() }
}
/**
* XML element
* @param reader [XMLEventReader] to be used for peeking at the next element in [content].
*/
@DSL
inner class Element(private val reader: XMLEventReader) {
private var startFunc: (() -> Unit)? = null
private var endFunc: (() -> Unit)? = null
private var event: XMLEvent? = null
internal fun parseStart(event: XMLEvent) {
this.event = event
startFunc?.invoke()
}
internal fun parseEnd() { endFunc?.invoke() }
/**
* Specify code to execute when encountering a starting tag of the specified element
* @param f code to execute
*/
fun start(f: () -> Unit) {
startFunc = f
}
/**
* Specify code to execute when encountering a closing tag of the specified element
* @param f code to execute
*/
fun end(f: () -> Unit) {
endFunc = f
}
/**
* Get the content of the current element
* @return content of current tag or null
*/
fun content(): String? {
return try {
reader.peek().asCharacters().data
} catch (e: ClassCastException) {
null
}
}
/**
* Get attribute of current element if it exists or null. Only works within a start element.
* @param attribute attribute name
* @return value of attribute or null
*/
fun attribute(attribute: String): String? =
event!!.asStartElement().getAttributeByName(QName(attribute))?.value
}
}
\ No newline at end of file
import guru.kake.ronove.DictionaryParser.Companion.parseKanjidic2
import guru.kake.ronove.RMGroup
import guru.kake.ronove.Sense
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class DictionaryParserTest {
@Test fun testCharacter() {
val c1 = guru.kake.ronove.Character("猫")
val c2 = guru.kake.ronove.Character("猫")
c2.rmgroups.add(RMGroup())
val c3 = guru.kake.ronove.Character("犬")
val c4 = guru.kake.ronove.Character("鳥")
val s = "cat"
assert(c1 == c2)
assert(c1 != c3)
assert(!c1.equals(s))
assert(!c1.equals(null))
assert(c1 > c3)
assert(c1 < c4)
assert(c1.hashCode() == c2.hashCode())
assert(c1.hashCode() != c3.hashCode())
}
@Test fun testPhrase() {
val p1 = guru.kake.ronove.Phrase("ねこ")
val p2 = guru.kake.ronove.Phrase("ねこ")
p2.senses.add(Sense())
val p3 = guru.kake.ronove.Phrase("いぬ")
val p4 = guru.kake.ronove.Phrase("わたし")
val s = "cat"
assert(p1 == p2)
assert(p1 != p3)
assert(!p1.equals(s))
assert(!p1.equals(null))
assert(p1 > p3)
assert(p1 < p4)
assert(p1.hashCode() == p2.hashCode())
assert(p1.hashCode() != p3.hashCode())
}
@Test fun testParseKanjidic2() {
val result = parseKanjidic2(kanjidic2sample.byteInputStream())
assertEquals("猫", result[0].literal)
assertEquals("ビョウ", result[0].rmgroups[0].reading.find { it.first == "ja_on" }?.second)
assertEquals("ねこ", result[0].rmgroups[0].reading.find { it.first == "ja_kun" }?.second)
assertEquals("cat", result[0].rmgroups[0].meaning.find { it.first == null }?.second)
assertEquals("gato", result[0].rmgroups[0].meaning.find { it.first == "es" }?.second)
}
companion object {
private val kanjidic2sample =
"<!-- Entry for Kanji: 猫 -->\n" +
"<character>\n" +
"<literal>猫</literal>\n" +
"<codepoint>\n" +
"<cp_value cp_type=\"ucs\">732b</cp_value>\n" +
"<cp_value cp_type=\"jis208\">1-39-13</cp_value>\n" +
"</codepoint>\n" +
"<radical>\n" +
"<rad_value rad_type=\"classical\">94</rad_value>\n" +
"</radical>\n" +
"<misc>\n" +
"<grade>8</grade>\n" +
"<stroke_count>11</stroke_count>\n" +
"<variant var_type=\"jis212\">1-63-05</variant>\n" +
"<freq>1702</freq>\n" +
"<jlpt>2</jlpt>\n" +
"</misc>\n" +
"<dic_number>\n" +
"<dic_ref dr_type=\"nelson_c\">2893</dic_ref>\n" +
"<dic_ref dr_type=\"nelson_n\">3586</dic_ref>\n" +
"<dic_ref dr_type=\"halpern_njecd\">535</dic_ref>\n" +
"<dic_ref dr_type=\"halpern_kkd\">651</dic_ref>\n" +
"<dic_ref dr_type=\"halpern_kkld\">391</dic_ref>\n" +
"<dic_ref dr_type=\"halpern_kkld_2ed\">488</dic_ref>\n" +
"<dic_ref dr_type=\"heisig\">244</dic_ref>\n" +
"<dic_ref dr_type=\"heisig6\">259</dic_ref>\n" +
"<dic_ref dr_type=\"gakken\">1763</dic_ref>\n" +
"<dic_ref dr_type=\"oneill_names\">1304</dic_ref>\n" +
"<dic_ref dr_type=\"moro\" m_vol=\"7\" m_page=\"0719\">20535X</dic_ref>\n" +
"<dic_ref dr_type=\"henshall\">1742</dic_ref>\n" +
"<dic_ref dr_type=\"sh_kk\">1470</dic_ref>\n" +
"<dic_ref dr_type=\"sh_kk2\">1567</dic_ref>\n" +
"<dic_ref dr_type=\"jf_cards\">730</dic_ref>\n" +
"<dic_ref dr_type=\"tutt_cards\">1461</dic_ref>\n" +
"<dic_ref dr_type=\"kanji_in_context\">1410</dic_ref>\n" +
"<dic_ref dr_type=\"kodansha_compact\">1304</dic_ref>\n" +
"<dic_ref dr_type=\"maniette\">250</dic_ref>\n" +
"</dic_number>\n" +
"<query_code>\n" +
"<q_code qc_type=\"skip\">1-3-8</q_code>\n" +
"<q_code qc_type=\"sh_desc\">3g8.5</q_code>\n" +
"<q_code qc_type=\"four_corner\">4426.0</q_code>\n" +
"<q_code qc_type=\"deroo\">2976</q_code>\n" +
"</query_code>\n" +
"<reading_meaning>\n" +
"<rmgroup>\n" +
"<reading r_type=\"pinyin\">mao1</reading>\n" +
"<reading r_type=\"pinyin\">mao2</reading>\n" +
"<reading r_type=\"korean_r\">myo</reading>\n" +
"<reading r_type=\"korean_h\">묘</reading>\n" +
"<reading r_type=\"vietnam\">Miêu</reading>\n" +
"<reading r_type=\"ja_on\">ビョウ</reading>\n" +
"<reading r_type=\"ja_kun\">ねこ</reading>\n" +
"<meaning>cat</meaning>\n" +
"<meaning m_lang=\"fr\">chat</meaning>\n" +
"<meaning m_lang=\"es\">gato</meaning>\n" +
"<meaning m_lang=\"pt\">Gato</meaning>\n" +
"</rmgroup>\n" +
"</reading_meaning>\n" +
"</character>"
}
}
\ No newline at end of file
/*
@ExtendWith(ApplicationExtension::class)
class SplashScreenTest {
private val project = Project()
private lateinit var fragment : SplashScreen
@Suppress("Unused")
@Start private fun start(stage: Stage) {
fragment = SplashScreen(project)
fragment.openModal(stageStyle = StageStyle.UTILITY, block = false,
modality = Modality.APPLICATION_MODAL, owner = stage)
}
@Test fun splashTest(robot: FxRobot) {
robot.sleep(1000) //test can potentially fail if robot starts performing actions before window opens
}
}
*/
\ No newline at end of file
import guru.kake.ronove.TranslationBackend
import guru.kake.ronove.TranslationService
import guru.kake.ronove.TranslationServiceException
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
class MockTranslationService(private val mockKey: String = "") : TranslationService {
init {
if (mockKey == "wrong key") {
throw TranslationServiceException("Mocking wrong key entry")
}
}
override fun translate(text: String, sourceLang: String, destLang: String): String {
return when (destLang) {
"upper" -> text.uppercase()
"lower" -> text.lowercase()
"getkey" -> mockKey
else -> text
}
}
}
class TranslationBackendTest {
@BeforeEach fun init() {
TranslationBackend.setService(MockTranslationService(), "Mock")
}
@Test fun translateSingle() {
assertEquals(TranslationBackend("MixedCase","source","upper"),"MIXEDCASE")
assertEquals(TranslationBackend("MixedCase","source","lower"),"mixedcase")
TranslationBackend.destinationLanguage = "upper"
assertEquals(TranslationBackend("MixedCase"),"MIXEDCASE")
TranslationBackend.destinationLanguage = "lower"
assertEquals(TranslationBackend("MixedCase"),"mixedcase")
}
@Test fun translateMultiple() {
val list = listOf("One", "Two", "tHREE")
assertEquals(TranslationBackend(list,"source","upper"), listOf("ONE","TWO","THREE"))
assertEquals(TranslationBackend(list,"source","lower"), listOf("one","two","three"))
TranslationBackend.destinationLanguage = "lower"
assertEquals(TranslationBackend(list), listOf("one","two","three"))
TranslationBackend.destinationLanguage = "upper"
assertEquals(TranslationBackend(list), listOf("ONE","TWO","THREE"))
}
}
\ No newline at end of file
import guru.kake.ronove.*
import javafx.stage.Modality
import javafx.stage.Stage
import javafx.stage.StageStyle
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.testfx.api.FxRobot
import org.testfx.framework.junit5.ApplicationExtension
import org.testfx.framework.junit5.Start
import org.testfx.framework.junit5.Stop
import tornadofx.*
import kotlin.test.assertEquals
class DummyMainWindow : View("Test") {
override val root = pane {
label("Dummy")
}
}
@ExtendWith(ApplicationExtension::class)
class TranslationPageViewTest {
private val ronove = Ronove()
private lateinit var dummy: DummyMainWindow
private lateinit var fragment: TranslationPageView
@Suppress("Unused")
@Start private fun start(stage: Stage) {
assertEquals(0,ronove.pageCount.get())
for (i in 1..10) {
ronove.addPage()
}
assertEquals(10,ronove.pageCount.get())
dummy = DummyMainWindow()
dummy.openModal(stageStyle = StageStyle.UTILITY, block = false,
modality = Modality.APPLICATION_MODAL, owner = stage)
fragment = TranslationPageView(ronove)
fragment.openModal(stageStyle = StageStyle.UTILITY, block = false,
modality = Modality.APPLICATION_MODAL, owner = stage)
}
@Test fun pageJumpTest(robot: FxRobot) {
robot.clickOn("2"); assertEquals(2,ronove.currentPage.value)
robot.clickOn("1"); assertEquals(1,ronove.currentPage.value)
robot.clickOn("4"); assertEquals(4,ronove.currentPage.value)
robot.clickOn("3"); assertEquals(3,ronove.currentPage.value)
robot.clickOn("5"); assertEquals(5,ronove.currentPage.value)
robot.clickOn("<"); assertEquals(4,ronove.currentPage.value)
robot.clickOn("<"); assertEquals(3,ronove.currentPage.value)
robot.clickOn("<"); assertEquals(2,ronove.currentPage.value)
robot.clickOn(">>"); assertEquals(10,ronove.currentPage.value)
robot.clickOn("<<"); assertEquals(1,ronove.currentPage.value)
robot.clickOn(">"); assertEquals(2,ronove.currentPage.value)
robot.clickOn(">"); assertEquals(3,ronove.currentPage.value)
robot.clickOn(">"); assertEquals(4,ronove.currentPage.value)
robot.clickOn("+"); assertEquals(11,ronove.pageCount.get())
robot.clickOn("+"); assertEquals(12,ronove.pageCount.get())
}
@Test fun edit(robot: FxRobot) {
ronove.project.pages[2].lines.add(Line("a","b","c"))
ronove.project.pages[2].lines.add(Line("d","e","f"))
ronove.project.pages[2].lines.add(Line("g","h","i"))
robot.clickOn("3")
robot.doubleClickOn("f"); robot.write("foxtrot\n")
robot.doubleClickOn("e"); robot.write("echo\n")
robot.doubleClickOn("i"); robot.write("india\n")
robot.doubleClickOn("h"); robot.write("hotel\n")
robot.doubleClickOn("d"); robot.write("delta\n")
robot.doubleClickOn("b"); robot.write("bravo\n")
robot.doubleClickOn("a"); robot.write("alpha\n")
robot.doubleClickOn("g"); robot.write("golf\n")
robot.doubleClickOn("c"); robot.write("charlie\n")
assertEquals("[alpha, delta, golf]", ronove.project.pages[2].getColumn(Line::original).toString())
assertEquals("[bravo, echo, hotel]", ronove.project.pages[2].getColumn(Line::machineTranslation).toString())
assertEquals("[charlie, foxtrot, india]", ronove.project.pages[2].getColumn(Line::finalTranslation).toString())
}
@Suppress("Unused")
@Stop fun stop() {
fragment.close()
dummy.close()
}
}
\ No newline at end of file
import guru.kake.ronove.*
import javafx.stage.Modality
import javafx.stage.Stage
import javafx.stage.StageStyle
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.testfx.api.FxRobot
import org.testfx.framework.junit5.ApplicationExtension
import org.testfx.framework.junit5.Start
import org.testfx.framework.junit5.Stop
import tornadofx.*
import kotlin.test.assertEquals
@ExtendWith(ApplicationExtension::class)
class TranslationSettingsTest {
private lateinit var dummy: DummyMainWindow
private lateinit var fragment: TranslationSettings
@Suppress("Unused")
@Start private fun start(stage: Stage) {
val backends = mapOf<String, (String) -> TranslationService>(
"Backend 1" to {MockTranslationService(it)}
)
dummy = DummyMainWindow()
dummy.openModal(stageStyle = StageStyle.UTILITY, block = false,
modality = Modality.APPLICATION_MODAL, owner = stage)
fragment = TranslationSettings(backends)
fragment.openModal(stageStyle = StageStyle.UTILITY, block = false,
modality = Modality.APPLICATION_MODAL, owner = stage)
}
@Test fun translationSettingsTest(robot: FxRobot) {
robot.clickOn(".radio")
robot.clickOn(".field")
robot.write("wrong key")
robot.clickOn("Save & test")
robot.clickOn("Apply")
robot.point("Mocking wrong key entry")
robot.clickOn(".field")
robot.eraseText(10)
robot.write("right key")
robot.clickOn("Save & test")
robot.clickOn("Apply")
assertEquals(TranslationBackend("","","getkey"),"right key")
}
@Suppress("Unused")
@Stop fun stop() {
fragment.close()
dummy.close()
}
}
\ No newline at end of file
package guru.kake.bst
import org.junit.jupiter.api.Test
class MockNode(private val number: Int, val name: String = "") : Comparable<MockNode> {
override fun compareTo(other: MockNode): Int = number.compareTo(other.number)
}
class BSTTest {
@Test fun find() {
val list = listOf(
MockNode(1,"One"),
MockNode(3,"Three"),
MockNode(5,"Five"),
MockNode(8,"Eight"),
MockNode(9,"Nine"),
MockNode(6,"Six"),
MockNode(4,"Four"),
MockNode(2,"Two")
)
val bst = BST(list)
assert(bst.find(MockNode(1))?.name == "One")
assert(bst.find(MockNode(2))?.name == "Two")
assert(bst.find(MockNode(3))?.name == "Three")
assert(bst.find(MockNode(4))?.name == "Four")
assert(bst.find(MockNode(5))?.name == "Five")
assert(bst.find(MockNode(6))?.name == "Six")
assert(bst.find(MockNode(7))?.name == null)
assert(bst.find(MockNode(8))?.name == "Eight")
assert(bst.find(MockNode(9))?.name == "Nine")
}
}
\ No newline at end of file
package guru.kake.xmlp
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import kotlin.test.assertFailsWith
class XMLParserTest {
private val xml: String ="""
<tag>
<tag><cont foo="not" bar="not">one</cont><cont></cont></tag>
<tag><attr foo="two" bar="not">not</attr></tag>
<tag><tag><both foo="not" bar="three">four</both></tag></tag>
<attr foo="five" />
</tag>
""".trimIndent()
private val eof: String ="""
<tag><tag><tag></tag></tag>
""".trimIndent()
private val close: String ="""
<tag></tag></tag>
""".trimIndent()
@Test fun parseXML() {
val sb = StringBuilder()
XMLParser.parse(xml.byteInputStream()) {
element("cont") {
start { sb.append(content()?:"") }
}
element("attr") {
start { sb.append(attribute("foo"))}
}
element("both") {
start {
sb.append(content())
sb.append(attribute("bar"))
}
}
element("tag") {
start {
sb.append("{")
}
end{
sb.append("}")
}
}
}
assertEquals(sb.toString(),"{{one}{two}{{fourthree}}five}")
}
@Test fun malformed() {
assertFailsWith<com.ctc.wstx.exc.WstxEOFException> { XMLParser.parse(eof.byteInputStream()) {}}
assertFailsWith<com.ctc.wstx.exc.WstxParsingException> { XMLParser.parse(close.byteInputStream()) {}}
}
}
\ No newline at end of file