From d9b7b82c60e9f2197f16a959c8c33f87f370b0bb Mon Sep 17 00:00:00 2001 From: Marvin Elsen Date: Thu, 3 Oct 2024 12:11:50 +0200 Subject: [PATCH] Implement find characters --- src/main/kotlin/com/marvinelsen/willow/Model.kt | 14 +++++++++++++- .../com/marvinelsen/willow/WillowApplication.kt | 4 +++- .../willow/domain/SqliteDictionary.kt | 11 +++++++---- .../willow/ui/controllers/DetailsController.kt | 16 ++++++++++++++++ .../com/marvinelsen/willow/ui/util/Services.kt | 10 ++++++++++ src/main/resources/fxml/details.fxml | 11 +++++------ 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/com/marvinelsen/willow/Model.kt b/src/main/kotlin/com/marvinelsen/willow/Model.kt index 70ba514..3622d3f 100644 --- a/src/main/kotlin/com/marvinelsen/willow/Model.kt +++ b/src/main/kotlin/com/marvinelsen/willow/Model.kt @@ -3,6 +3,7 @@ package com.marvinelsen.willow import com.marvinelsen.willow.domain.SearchMode import com.marvinelsen.willow.ui.DictionaryEntryFx import com.marvinelsen.willow.ui.util.ClipboardHelper +import com.marvinelsen.willow.ui.util.FindCharacterService import com.marvinelsen.willow.ui.util.FindWordsService import com.marvinelsen.willow.ui.util.SearchService import javafx.beans.property.ObjectProperty @@ -13,10 +14,11 @@ import javafx.collections.FXCollections import javafx.collections.ObservableList import javafx.event.EventHandler -class Model(private val searchService: SearchService, private val findWordsService: FindWordsService) { +class Model(private val searchService: SearchService, private val findWordsService: FindWordsService, private val findCharacterService: FindCharacterService) { private val internalSelectedEntry: ObjectProperty = SimpleObjectProperty() private val internalSearchResults: ObservableList = FXCollections.observableArrayList() private val internalWordsContaining: ObservableList = FXCollections.observableArrayList() + private val internalCharacters: ObservableList = FXCollections.observableArrayList() val selectedEntry: ReadOnlyObjectProperty = internalSelectedEntry @@ -24,6 +26,8 @@ class Model(private val searchService: SearchService, private val findWordsServi FXCollections.unmodifiableObservableList(internalSearchResults) val wordsContaining: ObservableList = FXCollections.unmodifiableObservableList(internalWordsContaining) + val characters: ObservableList = + FXCollections.unmodifiableObservableList(internalCharacters) val isSearching: ReadOnlyBooleanProperty = searchService.runningProperty() val isFindingWords: ReadOnlyBooleanProperty = findWordsService.runningProperty() @@ -35,6 +39,9 @@ class Model(private val searchService: SearchService, private val findWordsServi findWordsService.onSucceeded = EventHandler { internalWordsContaining.setAll(findWordsService.value) } + findCharacterService.onSucceeded = EventHandler { + internalCharacters.setAll(findCharacterService.value) + } } fun search(query: String, searchMode: SearchMode) { @@ -48,6 +55,11 @@ class Model(private val searchService: SearchService, private val findWordsServi findWordsService.restart() } + fun findCharacters() { + findCharacterService.entry = internalSelectedEntry.value + findCharacterService.restart() + } + fun selectEntry(entry: DictionaryEntryFx) { internalSelectedEntry.value = entry } diff --git a/src/main/kotlin/com/marvinelsen/willow/WillowApplication.kt b/src/main/kotlin/com/marvinelsen/willow/WillowApplication.kt index d9130ba..2465bff 100644 --- a/src/main/kotlin/com/marvinelsen/willow/WillowApplication.kt +++ b/src/main/kotlin/com/marvinelsen/willow/WillowApplication.kt @@ -7,6 +7,7 @@ import com.marvinelsen.willow.ui.controllers.MainController import com.marvinelsen.willow.ui.controllers.MenuController import com.marvinelsen.willow.ui.controllers.SearchController import com.marvinelsen.willow.ui.controllers.SearchResultsController +import com.marvinelsen.willow.ui.util.FindCharacterService import com.marvinelsen.willow.ui.util.FindWordsService import com.marvinelsen.willow.ui.util.SearchService import javafx.application.Application @@ -44,7 +45,8 @@ class WillowApplication : Application() { val dictionary = SqliteDictionary(connection) val searchService = SearchService(dictionary) val findWordsService = FindWordsService(dictionary) - val model = Model(searchService, findWordsService) + val findCharacterService = FindCharacterService(dictionary) + val model = Model(searchService, findWordsService, findCharacterService) val config = Config() config.load() diff --git a/src/main/kotlin/com/marvinelsen/willow/domain/SqliteDictionary.kt b/src/main/kotlin/com/marvinelsen/willow/domain/SqliteDictionary.kt index d849764..a1d4d7a 100644 --- a/src/main/kotlin/com/marvinelsen/willow/domain/SqliteDictionary.kt +++ b/src/main/kotlin/com/marvinelsen/willow/domain/SqliteDictionary.kt @@ -78,9 +78,11 @@ class SqliteDictionary(private val connection: Connection) : Dictionary { } private val findCharacters = """ - SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, definitions - FROM cedict - WHERE traditional IN (?) + WITH cte(id, character) AS (VALUES ?) + SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, definitions + FROM cedict INNER JOIN cte + ON cte.character = cedict.traditional OR cte.character = cedict.simplified + ORDER BY cte.id """.trimIndent() override fun search(query: String, searchMode: SearchMode) = when (searchMode) { @@ -107,7 +109,8 @@ class SqliteDictionary(private val connection: Connection) : Dictionary { val characterList = entry.traditional .split("") .filter { it.isNotBlank() } - .joinToString(",") { "'$it'" } + .mapIndexed { index, s -> "($index, '$s')" } + .joinToString(",") val query = findCharacters.replace("?", characterList) diff --git a/src/main/kotlin/com/marvinelsen/willow/ui/controllers/DetailsController.kt b/src/main/kotlin/com/marvinelsen/willow/ui/controllers/DetailsController.kt index de63538..f811069 100644 --- a/src/main/kotlin/com/marvinelsen/willow/ui/controllers/DetailsController.kt +++ b/src/main/kotlin/com/marvinelsen/willow/ui/controllers/DetailsController.kt @@ -49,6 +49,7 @@ class DetailsController(private val model: Model, private val config: Config) { initializeLabelHeadword() initializeTabPaneDetails() initializeListViewWords() + initializeListViewCharacters() initializeWebViewDefinition() model.selectedEntry.addListener { _, _, newEntry -> @@ -59,6 +60,10 @@ class DetailsController(private val model: Model, private val config: Config) { model.findWords() } + "tabCharacters" -> { + model.findCharacters() + } + else -> {} } webViewDefinition.engine.loadContent(newEntry.createCedictDefinitionHtml()) @@ -78,6 +83,13 @@ class DetailsController(private val model: Model, private val config: Config) { } } + private fun initializeListViewCharacters() { + listViewCharacters.apply { + cellFactory = DictionaryEntryCellFactory(resources, config) + items = model.characters + } + } + private fun initializeTabPaneDetails() { tabPaneDetails.apply { disableProperty().bind(Bindings.isNull(model.selectedEntry)) @@ -90,6 +102,10 @@ class DetailsController(private val model: Model, private val config: Config) { model.findWords() } + "tabCharacters" -> { + model.findCharacters() + } + else -> {} } } diff --git a/src/main/kotlin/com/marvinelsen/willow/ui/util/Services.kt b/src/main/kotlin/com/marvinelsen/willow/ui/util/Services.kt index bb256ee..18df8ba 100644 --- a/src/main/kotlin/com/marvinelsen/willow/ui/util/Services.kt +++ b/src/main/kotlin/com/marvinelsen/willow/ui/util/Services.kt @@ -30,3 +30,13 @@ class FindWordsService(private val dictionary: Dictionary) : Service>() { + lateinit var entry: DictionaryEntryFx + + override fun createTask() = task { + if (!this::entry.isInitialized) error("Entry is not initialized") + + FXCollections.observableList(dictionary.findCharacters(entry.toDomain()).map { it.toFx() }) + } +} diff --git a/src/main/resources/fxml/details.fxml b/src/main/resources/fxml/details.fxml index 2aa60ab..0c05f6f 100644 --- a/src/main/resources/fxml/details.fxml +++ b/src/main/resources/fxml/details.fxml @@ -14,17 +14,16 @@ - - + + - + - + - +