Implement find characters

This commit is contained in:
Marvin Elsen 2024-10-03 12:11:50 +02:00
parent cb52240eea
commit d9b7b82c60
Signed by: marvinelsen
GPG Key ID: 820672408CC318C2
6 changed files with 54 additions and 12 deletions

View File

@ -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<DictionaryEntryFx> = SimpleObjectProperty()
private val internalSearchResults: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
private val internalWordsContaining: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
private val internalCharacters: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
val selectedEntry: ReadOnlyObjectProperty<DictionaryEntryFx> = internalSelectedEntry
@ -24,6 +26,8 @@ class Model(private val searchService: SearchService, private val findWordsServi
FXCollections.unmodifiableObservableList(internalSearchResults)
val wordsContaining: ObservableList<DictionaryEntryFx> =
FXCollections.unmodifiableObservableList(internalWordsContaining)
val characters: ObservableList<DictionaryEntryFx> =
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
}

View File

@ -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()

View File

@ -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)

View File

@ -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 -> {}
}
}

View File

@ -30,3 +30,13 @@ class FindWordsService(private val dictionary: Dictionary) : Service<ObservableL
FXCollections.observableList(dictionary.findWordsContaining(entry.toDomain()).map { it.toFx() })
}
}
class FindCharacterService(private val dictionary: Dictionary) : Service<ObservableList<DictionaryEntryFx>>() {
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() })
}
}

View File

@ -14,17 +14,16 @@
</padding>
</Label>
<TabPane fx:id="tabPaneDetails" tabClosingPolicy="UNAVAILABLE" disable="true" VBox.vgrow="ALWAYS">
<Tab closable="false" disable="false" text="%tab.definition">
<WebView fx:id="webViewDefinition" minHeight="-1.0" minWidth="-1.0" prefHeight="-1.0"
prefWidth="-1.0"/>
<Tab closable="false" text="%tab.definition">
<WebView fx:id="webViewDefinition" minHeight="-1.0" minWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0"/>
</Tab>
<Tab id="tabSentences" closable="false" disable="false" text="%tab.sentences">
<Tab id="tabSentences" closable="false" text="%tab.sentences">
<ListView fx:id="listviewSentences"/>
</Tab>
<Tab id="tabWords" closable="false" disable="false" text="%tab.words">
<Tab id="tabWords" closable="false" text="%tab.words">
<ListView fx:id="listViewWords"/>
</Tab>
<Tab closable="false" disable="false" text="%tab.characters">
<Tab id="tabCharacters" closable="false" text="%tab.characters">
<ListView fx:id="listViewCharacters"/>
</Tab>
</TabPane>