Implement find sentence function
This commit is contained in:
parent
50017f45c4
commit
168d1634a2
@ -2,7 +2,9 @@ package com.marvinelsen.willow
|
|||||||
|
|
||||||
import com.marvinelsen.willow.domain.SearchMode
|
import com.marvinelsen.willow.domain.SearchMode
|
||||||
import com.marvinelsen.willow.ui.DictionaryEntryFx
|
import com.marvinelsen.willow.ui.DictionaryEntryFx
|
||||||
|
import com.marvinelsen.willow.ui.SentenceFx
|
||||||
import com.marvinelsen.willow.ui.services.FindCharacterService
|
import com.marvinelsen.willow.ui.services.FindCharacterService
|
||||||
|
import com.marvinelsen.willow.ui.services.FindSentencesService
|
||||||
import com.marvinelsen.willow.ui.services.FindWordsService
|
import com.marvinelsen.willow.ui.services.FindWordsService
|
||||||
import com.marvinelsen.willow.ui.services.SearchService
|
import com.marvinelsen.willow.ui.services.SearchService
|
||||||
import com.marvinelsen.willow.ui.util.ClipboardHelper
|
import com.marvinelsen.willow.ui.util.ClipboardHelper
|
||||||
@ -18,11 +20,13 @@ class Model(
|
|||||||
private val searchService: SearchService,
|
private val searchService: SearchService,
|
||||||
private val findWordsService: FindWordsService,
|
private val findWordsService: FindWordsService,
|
||||||
private val findCharacterService: FindCharacterService,
|
private val findCharacterService: FindCharacterService,
|
||||||
|
private val findSentencesService: FindSentencesService,
|
||||||
) {
|
) {
|
||||||
private val internalSelectedEntry: ObjectProperty<DictionaryEntryFx> = SimpleObjectProperty()
|
private val internalSelectedEntry: ObjectProperty<DictionaryEntryFx> = SimpleObjectProperty()
|
||||||
private val internalSearchResults: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
|
private val internalSearchResults: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
|
||||||
private val internalWordsContaining: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
|
private val internalWordsContaining: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
|
||||||
private val internalCharacters: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
|
private val internalCharacters: ObservableList<DictionaryEntryFx> = FXCollections.observableArrayList()
|
||||||
|
private val internalSentences: ObservableList<SentenceFx> = FXCollections.observableArrayList()
|
||||||
|
|
||||||
val selectedEntry: ReadOnlyObjectProperty<DictionaryEntryFx> = internalSelectedEntry
|
val selectedEntry: ReadOnlyObjectProperty<DictionaryEntryFx> = internalSelectedEntry
|
||||||
|
|
||||||
@ -32,10 +36,13 @@ class Model(
|
|||||||
FXCollections.unmodifiableObservableList(internalWordsContaining)
|
FXCollections.unmodifiableObservableList(internalWordsContaining)
|
||||||
val characters: ObservableList<DictionaryEntryFx> =
|
val characters: ObservableList<DictionaryEntryFx> =
|
||||||
FXCollections.unmodifiableObservableList(internalCharacters)
|
FXCollections.unmodifiableObservableList(internalCharacters)
|
||||||
|
val sentences: ObservableList<SentenceFx> =
|
||||||
|
FXCollections.unmodifiableObservableList(internalSentences)
|
||||||
|
|
||||||
val isSearching: ReadOnlyBooleanProperty = searchService.runningProperty()
|
val isSearching: ReadOnlyBooleanProperty = searchService.runningProperty()
|
||||||
val isFindingWords: ReadOnlyBooleanProperty = findWordsService.runningProperty()
|
val isFindingWords: ReadOnlyBooleanProperty = findWordsService.runningProperty()
|
||||||
val isFindingCharacters: ReadOnlyBooleanProperty = findCharacterService.runningProperty()
|
val isFindingCharacters: ReadOnlyBooleanProperty = findCharacterService.runningProperty()
|
||||||
|
val isFindingSentences: ReadOnlyBooleanProperty = findSentencesService.runningProperty()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
searchService.onSucceeded = EventHandler {
|
searchService.onSucceeded = EventHandler {
|
||||||
@ -47,6 +54,9 @@ class Model(
|
|||||||
findCharacterService.onSucceeded = EventHandler {
|
findCharacterService.onSucceeded = EventHandler {
|
||||||
internalCharacters.setAll(findCharacterService.value)
|
internalCharacters.setAll(findCharacterService.value)
|
||||||
}
|
}
|
||||||
|
findSentencesService.onSucceeded = EventHandler {
|
||||||
|
internalSentences.setAll(findSentencesService.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(query: String, searchMode: SearchMode) {
|
fun search(query: String, searchMode: SearchMode) {
|
||||||
@ -65,9 +75,15 @@ class Model(
|
|||||||
findCharacterService.restart()
|
findCharacterService.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun findSentences() {
|
||||||
|
findSentencesService.entry = internalSelectedEntry.value
|
||||||
|
findSentencesService.restart()
|
||||||
|
}
|
||||||
|
|
||||||
fun selectEntry(entry: DictionaryEntryFx) {
|
fun selectEntry(entry: DictionaryEntryFx) {
|
||||||
internalWordsContaining.setAll(emptyList())
|
internalWordsContaining.setAll(emptyList())
|
||||||
internalCharacters.setAll(emptyList())
|
internalCharacters.setAll(emptyList())
|
||||||
|
internalSentences.setAll(emptyList())
|
||||||
internalSelectedEntry.value = entry
|
internalSelectedEntry.value = entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import com.marvinelsen.willow.ui.controllers.MenuController
|
|||||||
import com.marvinelsen.willow.ui.controllers.SearchController
|
import com.marvinelsen.willow.ui.controllers.SearchController
|
||||||
import com.marvinelsen.willow.ui.controllers.SearchResultsController
|
import com.marvinelsen.willow.ui.controllers.SearchResultsController
|
||||||
import com.marvinelsen.willow.ui.services.FindCharacterService
|
import com.marvinelsen.willow.ui.services.FindCharacterService
|
||||||
|
import com.marvinelsen.willow.ui.services.FindSentencesService
|
||||||
import com.marvinelsen.willow.ui.services.FindWordsService
|
import com.marvinelsen.willow.ui.services.FindWordsService
|
||||||
import com.marvinelsen.willow.ui.services.SearchService
|
import com.marvinelsen.willow.ui.services.SearchService
|
||||||
import javafx.application.Application
|
import javafx.application.Application
|
||||||
@ -46,7 +47,8 @@ class WillowApplication : Application() {
|
|||||||
val searchService = SearchService(dictionary)
|
val searchService = SearchService(dictionary)
|
||||||
val findWordsService = FindWordsService(dictionary)
|
val findWordsService = FindWordsService(dictionary)
|
||||||
val findCharacterService = FindCharacterService(dictionary)
|
val findCharacterService = FindCharacterService(dictionary)
|
||||||
val model = Model(searchService, findWordsService, findCharacterService)
|
val findSentenceService = FindSentencesService(dictionary)
|
||||||
|
val model = Model(searchService, findWordsService, findCharacterService, findSentenceService)
|
||||||
val config = Config()
|
val config = Config()
|
||||||
config.load()
|
config.load()
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ package com.marvinelsen.willow.domain
|
|||||||
interface Dictionary {
|
interface Dictionary {
|
||||||
fun search(query: String, searchMode: SearchMode): List<DictionaryEntry>
|
fun search(query: String, searchMode: SearchMode): List<DictionaryEntry>
|
||||||
fun findWordsContaining(entry: DictionaryEntry): List<DictionaryEntry>
|
fun findWordsContaining(entry: DictionaryEntry): List<DictionaryEntry>
|
||||||
fun findSentencesContaining(entry: DictionaryEntry): List<DictionaryEntry>
|
fun findSentencesContaining(entry: DictionaryEntry): List<Sentence>
|
||||||
fun findCharacters(entry: DictionaryEntry): List<DictionaryEntry>
|
fun findCharacters(entry: DictionaryEntry): List<DictionaryEntry>
|
||||||
fun searchSegments(phrase: String): List<DictionaryEntry>
|
fun searchSegments(phrase: String): List<DictionaryEntry>
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,17 @@ class SqliteDictionary(private val connection: Connection) : Dictionary {
|
|||||||
ORDER BY cte.id
|
ORDER BY cte.id
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
|
private val findSentences: PreparedStatement by lazy {
|
||||||
|
connection.prepareStatement(
|
||||||
|
"""
|
||||||
|
SELECT traditional, simplified
|
||||||
|
FROM sentence
|
||||||
|
WHERE traditional LIKE ?
|
||||||
|
ORDER BY character_count ASC
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun search(query: String, searchMode: SearchMode) = when (searchMode) {
|
override fun search(query: String, searchMode: SearchMode) = when (searchMode) {
|
||||||
SearchMode.PINYIN -> searchPinyin(query)
|
SearchMode.PINYIN -> searchPinyin(query)
|
||||||
SearchMode.SIMPLIFIED -> searchSimplified(query)
|
SearchMode.SIMPLIFIED -> searchSimplified(query)
|
||||||
@ -101,8 +112,12 @@ class SqliteDictionary(private val connection: Connection) : Dictionary {
|
|||||||
return resultSet.toListOfDictionaryEntries()
|
return resultSet.toListOfDictionaryEntries()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findSentencesContaining(entry: DictionaryEntry): List<DictionaryEntry> {
|
override fun findSentencesContaining(entry: DictionaryEntry): List<Sentence> {
|
||||||
return emptyList()
|
findSentences.setString(1, "_%${entry.traditional}%")
|
||||||
|
|
||||||
|
val resultSet: ResultSet = findSentences.executeQuery()
|
||||||
|
|
||||||
|
return resultSet.toListOfSentences()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findCharacters(entry: DictionaryEntry): List<DictionaryEntry> {
|
override fun findCharacters(entry: DictionaryEntry): List<DictionaryEntry> {
|
||||||
@ -191,3 +206,16 @@ private fun ResultSet.toListOfDictionaryEntries() = buildList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ResultSet.toSentence() = Sentence(
|
||||||
|
traditional = this.getString(1),
|
||||||
|
simplified = this.getString(2),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun ResultSet.toListOfSentences() = buildList {
|
||||||
|
this@toListOfSentences.use {
|
||||||
|
while (it.next()) {
|
||||||
|
add(it.toSentence())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
20
src/main/kotlin/com/marvinelsen/willow/ui/SentenceFx.kt
Normal file
20
src/main/kotlin/com/marvinelsen/willow/ui/SentenceFx.kt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.marvinelsen.willow.ui
|
||||||
|
|
||||||
|
import com.marvinelsen.willow.domain.Sentence
|
||||||
|
import javafx.beans.property.SimpleStringProperty
|
||||||
|
import javafx.beans.property.StringProperty
|
||||||
|
|
||||||
|
data class SentenceFx(
|
||||||
|
val traditionalProperty: StringProperty,
|
||||||
|
val simplifiedProperty: StringProperty,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Sentence.toFx() = SentenceFx(
|
||||||
|
traditionalProperty = SimpleStringProperty(this.traditional),
|
||||||
|
simplifiedProperty = SimpleStringProperty(this.simplified),
|
||||||
|
)
|
||||||
|
|
||||||
|
fun SentenceFx.toDomain() = Sentence(
|
||||||
|
traditional = this.traditionalProperty.value,
|
||||||
|
simplified = this.simplifiedProperty.value,
|
||||||
|
)
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.marvinelsen.willow.ui.cells
|
||||||
|
|
||||||
|
import com.marvinelsen.willow.ui.SentenceFx
|
||||||
|
import javafx.scene.control.Label
|
||||||
|
import javafx.scene.control.ListCell
|
||||||
|
import javafx.scene.control.ListView
|
||||||
|
import javafx.scene.layout.VBox
|
||||||
|
import javafx.util.Callback
|
||||||
|
|
||||||
|
class SentenceCellFactory() : Callback<ListView<SentenceFx?>, ListCell<SentenceFx?>> {
|
||||||
|
|
||||||
|
override fun call(listView: ListView<SentenceFx?>): ListCell<SentenceFx?> {
|
||||||
|
val sentenceCell = SentenceCell()
|
||||||
|
sentenceCell.prefWidthProperty().bind(listView.widthProperty().subtract(CELL_PADDING))
|
||||||
|
return sentenceCell
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CELL_PADDING = 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class SentenceCell() : ListCell<SentenceFx?>() {
|
||||||
|
private val labelTraditional = Label().apply {
|
||||||
|
styleClass.add("chinese")
|
||||||
|
styleClass.add("list-view-sentence-cell")
|
||||||
|
}
|
||||||
|
private val root = VBox(labelTraditional)
|
||||||
|
|
||||||
|
init {
|
||||||
|
text = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateItem(sentence: SentenceFx?, empty: Boolean) {
|
||||||
|
super.updateItem(sentence, empty)
|
||||||
|
if (empty || sentence == null) {
|
||||||
|
graphic = null
|
||||||
|
} else {
|
||||||
|
labelTraditional.text = sentence.traditionalProperty.value
|
||||||
|
|
||||||
|
graphic = root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,9 @@ import com.marvinelsen.willow.config.Config
|
|||||||
import com.marvinelsen.willow.config.Pronunciation
|
import com.marvinelsen.willow.config.Pronunciation
|
||||||
import com.marvinelsen.willow.config.Script
|
import com.marvinelsen.willow.config.Script
|
||||||
import com.marvinelsen.willow.ui.DictionaryEntryFx
|
import com.marvinelsen.willow.ui.DictionaryEntryFx
|
||||||
|
import com.marvinelsen.willow.ui.SentenceFx
|
||||||
import com.marvinelsen.willow.ui.cells.DictionaryEntryCellFactory
|
import com.marvinelsen.willow.ui.cells.DictionaryEntryCellFactory
|
||||||
|
import com.marvinelsen.willow.ui.cells.SentenceCellFactory
|
||||||
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
|
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
|
||||||
import javafx.beans.binding.Bindings
|
import javafx.beans.binding.Bindings
|
||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
@ -68,6 +70,16 @@ class DetailsController(private val model: Model, private val config: Config) {
|
|||||||
@FXML
|
@FXML
|
||||||
private lateinit var labelNoWordsFound: Label
|
private lateinit var labelNoWordsFound: Label
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private lateinit var listViewSentences: ListView<SentenceFx>
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private lateinit var progressIndicatorSentences: ProgressIndicator
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private lateinit var labelNoSentencesFound: Label
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
initializeLabelHeadword()
|
initializeLabelHeadword()
|
||||||
@ -75,6 +87,7 @@ class DetailsController(private val model: Model, private val config: Config) {
|
|||||||
initializeTabPaneDetails()
|
initializeTabPaneDetails()
|
||||||
initializeListViewWords()
|
initializeListViewWords()
|
||||||
initializeListViewCharacters()
|
initializeListViewCharacters()
|
||||||
|
initializeListViewSentences()
|
||||||
initializeWebViewDefinition()
|
initializeWebViewDefinition()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +180,19 @@ class DetailsController(private val model: Model, private val config: Config) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initializeListViewSentences() {
|
||||||
|
listViewSentences.apply {
|
||||||
|
cellFactory = SentenceCellFactory()
|
||||||
|
items = model.sentences
|
||||||
|
|
||||||
|
disableProperty().bind(Bindings.or(model.isFindingSentences, Bindings.isEmpty(model.sentences)))
|
||||||
|
}
|
||||||
|
progressIndicatorSentences.visibleProperty().bind(model.isFindingSentences)
|
||||||
|
labelNoSentencesFound
|
||||||
|
.visibleProperty()
|
||||||
|
.bind(Bindings.and(Bindings.isEmpty(model.sentences), Bindings.not(model.isFindingSentences)))
|
||||||
|
}
|
||||||
|
|
||||||
private fun initializeListViewWords() {
|
private fun initializeListViewWords() {
|
||||||
listViewWords.apply {
|
listViewWords.apply {
|
||||||
cellFactory = DictionaryEntryCellFactory(resources, config)
|
cellFactory = DictionaryEntryCellFactory(resources, config)
|
||||||
@ -324,6 +350,12 @@ class DetailsController(private val model: Model, private val config: Config) {
|
|||||||
model.findCharacters()
|
model.findCharacters()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"tabSentences" -> {
|
||||||
|
if (model.sentences.isNotEmpty()) return
|
||||||
|
|
||||||
|
model.findSentences()
|
||||||
|
}
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.marvinelsen.willow.ui.services
|
||||||
|
|
||||||
|
import com.marvinelsen.willow.domain.Dictionary
|
||||||
|
import com.marvinelsen.willow.ui.DictionaryEntryFx
|
||||||
|
import com.marvinelsen.willow.ui.SentenceFx
|
||||||
|
import com.marvinelsen.willow.ui.toDomain
|
||||||
|
import com.marvinelsen.willow.ui.toFx
|
||||||
|
import com.marvinelsen.willow.ui.util.task
|
||||||
|
import javafx.collections.FXCollections
|
||||||
|
import javafx.collections.ObservableList
|
||||||
|
import javafx.concurrent.Service
|
||||||
|
|
||||||
|
class FindSentencesService(private val dictionary: Dictionary) : Service<ObservableList<SentenceFx>>() {
|
||||||
|
lateinit var entry: DictionaryEntryFx
|
||||||
|
|
||||||
|
override fun createTask() = task {
|
||||||
|
if (!this::entry.isInitialized) error("Entry is not initialized")
|
||||||
|
|
||||||
|
FXCollections.observableList(dictionary.findSentencesContaining(entry.toDomain()).map { it.toFx() })
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,16 @@
|
|||||||
<WebView fx:id="webViewDefinition" minHeight="-1.0" minWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0"/>
|
<WebView fx:id="webViewDefinition" minHeight="-1.0" minWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0"/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="tabSentences" closable="false" text="%tab.sentences">
|
<Tab id="tabSentences" closable="false" text="%tab.sentences">
|
||||||
<ListView fx:id="listViewSentences"/>
|
<StackPane>
|
||||||
|
<ProgressIndicator fx:id="progressIndicatorSentences" visible="false"/>
|
||||||
|
<Label fx:id="labelNoSentencesFound" text="%list.no_sentences_found" textAlignment="CENTER" visible="false"
|
||||||
|
wrapText="true">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0"/>
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<ListView fx:id="listViewSentences"/>
|
||||||
|
</StackPane>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="tabWords" closable="false" text="%tab.words">
|
<Tab id="tabWords" closable="false" text="%tab.words">
|
||||||
<StackPane>
|
<StackPane>
|
||||||
|
@ -20,3 +20,4 @@ list.no_entries_found=No matching entries found
|
|||||||
search.mode.phrase=Phrase
|
search.mode.phrase=Phrase
|
||||||
list.no_characters_found=No characters found
|
list.no_characters_found=No characters found
|
||||||
list.no_words_found=No words found
|
list.no_words_found=No words found
|
||||||
|
list.no_sentences_found=No sentences found.
|
||||||
|
@ -20,3 +20,4 @@ list.no_entries_found=No matching entries found
|
|||||||
search.mode.phrase=Phrase
|
search.mode.phrase=Phrase
|
||||||
list.no_characters_found=No characters found
|
list.no_characters_found=No characters found
|
||||||
list.no_words_found=No words found
|
list.no_words_found=No words found
|
||||||
|
list.no_sentences_found=No sentences found.
|
||||||
|
@ -20,3 +20,4 @@ list.no_entries_found=No matching entries found
|
|||||||
search.mode.phrase=Phrase
|
search.mode.phrase=Phrase
|
||||||
list.no_characters_found=No characters found
|
list.no_characters_found=No characters found
|
||||||
list.no_words_found=No words found
|
list.no_words_found=No words found
|
||||||
|
list.no_sentences_found=No sentences found.
|
||||||
|
@ -20,3 +20,4 @@ list.no_entries_found=No matching entries found
|
|||||||
search.mode.phrase=Phrase
|
search.mode.phrase=Phrase
|
||||||
list.no_characters_found=No characters found
|
list.no_characters_found=No characters found
|
||||||
list.no_words_found=No words found
|
list.no_words_found=No words found
|
||||||
|
list.no_sentences_found=No sentences found.
|
||||||
|
@ -20,3 +20,4 @@ list.no_entries_found=No matching entries found
|
|||||||
search.mode.phrase=Phrase
|
search.mode.phrase=Phrase
|
||||||
list.no_characters_found=No characters found
|
list.no_characters_found=No characters found
|
||||||
list.no_words_found=No words found
|
list.no_words_found=No words found
|
||||||
|
list.no_sentences_found=No sentences found.
|
||||||
|
Loading…
Reference in New Issue
Block a user