Compare commits
No commits in common. "a2dfc858f46804b913db2e76d3cbd356b15f8951" and "52acfeb5da5f23271693fea89caeb12752839897" have entirely different histories.
a2dfc858f4
...
52acfeb5da
@ -1,127 +0,0 @@
|
|||||||
package com.marvinelsen.willow
|
|
||||||
|
|
||||||
import com.marvinelsen.willow.domain.SearchMode
|
|
||||||
import com.marvinelsen.willow.domain.SqliteDictionary
|
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
|
||||||
import com.marvinelsen.willow.ui.undo.Command
|
|
||||||
import com.marvinelsen.willow.ui.util.ClipboardHelper
|
|
||||||
import kotlinx.coroutines.MainScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Suppress("TooManyFunctions")
|
|
||||||
class Interactor(
|
|
||||||
private val model: Model,
|
|
||||||
private val dictionary: SqliteDictionary,
|
|
||||||
) {
|
|
||||||
private val coroutineScope = MainScope()
|
|
||||||
|
|
||||||
fun copyHeadwordOfSelectedEntry() {
|
|
||||||
model.selectedEntry?.let { ClipboardHelper.copyString(it.traditional) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun copyPronunciationOfSelectedEntry() {
|
|
||||||
model.selectedEntry?.let { ClipboardHelper.copyString(it.pinyinWithToneMarks) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun undoSelection() {
|
|
||||||
model.undoManager.undo()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun redoSelection() {
|
|
||||||
model.undoManager.redo()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun search(query: String, searchMode: SearchMode) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
model.isSearching = true
|
|
||||||
model.searchResults.setAll(dictionary.search(query, searchMode))
|
|
||||||
model.isSearching = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findWordsBeginning() {
|
|
||||||
coroutineScope.launch {
|
|
||||||
model.isFindingWordsBeginning = true
|
|
||||||
model.wordsBeginning.setAll(
|
|
||||||
model.selectedEntry?.let {
|
|
||||||
dictionary
|
|
||||||
.findWordsBeginningWith(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
model.isFindingWordsBeginning = false
|
|
||||||
model.finishedFindingWordsBeginning = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findWordsContaining() {
|
|
||||||
coroutineScope.launch {
|
|
||||||
model.isFindingWordsContaining = true
|
|
||||||
model.wordsContaining.setAll(
|
|
||||||
model.selectedEntry?.let {
|
|
||||||
dictionary
|
|
||||||
.findWordsContaining(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
model.isFindingWordsContaining = false
|
|
||||||
model.finishedFindingWordsContaining = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findCharacters() {
|
|
||||||
coroutineScope.launch {
|
|
||||||
model.isFindingCharacters = true
|
|
||||||
model.characters.setAll(
|
|
||||||
model.selectedEntry?.let {
|
|
||||||
dictionary
|
|
||||||
.findCharactersOf(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
model.isFindingCharacters = false
|
|
||||||
model.finishedFindingCharacters = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findSentences() {
|
|
||||||
coroutineScope.launch {
|
|
||||||
model.isFindingSentences = true
|
|
||||||
model.sentences.setAll(
|
|
||||||
model.selectedEntry?.let {
|
|
||||||
dictionary
|
|
||||||
.findExampleSentencesFor(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
model.isFindingSentences = false
|
|
||||||
model.finishedFindingSentences = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun deepDive(entry: DictionaryEntry) {
|
|
||||||
model.undoManager.execute(object : Command {
|
|
||||||
private val previouslySelectedEntry = model.selectedEntry
|
|
||||||
|
|
||||||
override fun execute() {
|
|
||||||
select(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun undo() {
|
|
||||||
if (previouslySelectedEntry == null) return
|
|
||||||
|
|
||||||
select(previouslySelectedEntry)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun normalSelect(entry: DictionaryEntry) {
|
|
||||||
model.undoManager.reset()
|
|
||||||
select(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun select(entry: DictionaryEntry) {
|
|
||||||
model.finishedFindingCharacters = false
|
|
||||||
model.finishedFindingWordsBeginning = false
|
|
||||||
model.finishedFindingWordsContaining = false
|
|
||||||
model.finishedFindingSentences = false
|
|
||||||
|
|
||||||
model.selectedEntry = entry
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,110 +1,169 @@
|
|||||||
package com.marvinelsen.willow
|
package com.marvinelsen.willow
|
||||||
|
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
import com.marvinelsen.willow.domain.SearchMode
|
||||||
import com.marvinelsen.willow.domain.objects.Sentence
|
import com.marvinelsen.willow.domain.SqliteDictionary
|
||||||
|
import com.marvinelsen.willow.domain.entities.DictionaryEntry
|
||||||
|
import com.marvinelsen.willow.domain.entities.Sentence
|
||||||
|
import com.marvinelsen.willow.ui.undo.Command
|
||||||
import com.marvinelsen.willow.ui.undo.UndoManager
|
import com.marvinelsen.willow.ui.undo.UndoManager
|
||||||
|
import com.marvinelsen.willow.ui.util.ClipboardHelper
|
||||||
import javafx.beans.property.BooleanProperty
|
import javafx.beans.property.BooleanProperty
|
||||||
import javafx.beans.property.ObjectProperty
|
import javafx.beans.property.ObjectProperty
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty
|
import javafx.beans.property.ReadOnlyBooleanProperty
|
||||||
|
import javafx.beans.property.ReadOnlyObjectProperty
|
||||||
import javafx.beans.property.SimpleBooleanProperty
|
import javafx.beans.property.SimpleBooleanProperty
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.collections.FXCollections
|
import javafx.collections.FXCollections
|
||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Suppress("TooManyFunctions")
|
@Suppress("TooManyFunctions")
|
||||||
class Model(
|
class Model(
|
||||||
val undoManager: UndoManager,
|
private val dictionary: SqliteDictionary,
|
||||||
|
private val undoManager: UndoManager,
|
||||||
) {
|
) {
|
||||||
private val _selectedEntry: ObjectProperty<DictionaryEntry?> = SimpleObjectProperty<DictionaryEntry>()
|
private val internalSelectedEntry: ObjectProperty<DictionaryEntry> = SimpleObjectProperty()
|
||||||
|
private val internalSearchResults: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
||||||
|
private val internalWordsBeginning: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
||||||
|
private val internalWordsContaining: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
||||||
|
private val internalCharacters: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
||||||
|
private val internalSentences: ObservableList<Sentence> = FXCollections.observableArrayList()
|
||||||
|
|
||||||
private val _isSearching: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalIsSearching: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
private val _isFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalIsFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
private val _isFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalIsFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
private val _isFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalIsFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
private val _isFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalIsFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
|
|
||||||
private val _finishedFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalFinishedFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
private val _finishedFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalFinishedFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
private val _finishedFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalFinishedFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
private val _finishedFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
|
private val internalFinishedFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
|
||||||
|
|
||||||
val searchResults: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
|
||||||
val wordsBeginning: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
|
||||||
val wordsContaining: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
|
||||||
val characters: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
|
|
||||||
val sentences: ObservableList<Sentence> = FXCollections.observableArrayList()
|
|
||||||
|
|
||||||
val canUndo: ReadOnlyBooleanProperty = undoManager.canUndoProperty
|
val canUndo: ReadOnlyBooleanProperty = undoManager.canUndoProperty
|
||||||
val canRedo: ReadOnlyBooleanProperty = undoManager.canRedoProperty
|
val canRedo: ReadOnlyBooleanProperty = undoManager.canRedoProperty
|
||||||
|
|
||||||
var selectedEntry: DictionaryEntry?
|
val selectedEntry: ReadOnlyObjectProperty<DictionaryEntry> = internalSelectedEntry
|
||||||
get() = _selectedEntry.value
|
|
||||||
set(value) {
|
|
||||||
_selectedEntry.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var isSearching: Boolean
|
val searchResults: ObservableList<DictionaryEntry> =
|
||||||
get() = _isSearching.value
|
FXCollections.unmodifiableObservableList(internalSearchResults)
|
||||||
set(value) {
|
val wordsBeginning: ObservableList<DictionaryEntry> =
|
||||||
_isSearching.value = value
|
FXCollections.unmodifiableObservableList(internalWordsBeginning)
|
||||||
}
|
val wordsContaining: ObservableList<DictionaryEntry> =
|
||||||
|
FXCollections.unmodifiableObservableList(internalWordsContaining)
|
||||||
|
val characters: ObservableList<DictionaryEntry> =
|
||||||
|
FXCollections.unmodifiableObservableList(internalCharacters)
|
||||||
|
val sentences: ObservableList<Sentence> =
|
||||||
|
FXCollections.unmodifiableObservableList(internalSentences)
|
||||||
|
|
||||||
var isFindingWordsBeginning: Boolean
|
val isSearching: ReadOnlyBooleanProperty = internalIsSearching
|
||||||
get() = _isFindingWordsBeginning.value
|
val isFindingWordsBeginning: ReadOnlyBooleanProperty = internalIsFindingWordsBeginning
|
||||||
set(value) {
|
val isFindingWordsContaining: ReadOnlyBooleanProperty = internalIsFindingWordsContaining
|
||||||
_isFindingWordsBeginning.value = value
|
val isFindingCharacters: ReadOnlyBooleanProperty = internalIsFindingCharacters
|
||||||
}
|
val isFindingSentences: ReadOnlyBooleanProperty = internalIsFindingSentences
|
||||||
|
|
||||||
var isFindingWordsContaining: Boolean
|
val finishedFindingWordsBeginning: ReadOnlyBooleanProperty = internalFinishedFindingWordsBeginning
|
||||||
get() = _isFindingWordsContaining.value
|
val finishedFindingWordsContaining: ReadOnlyBooleanProperty = internalFinishedFindingWordsContaining
|
||||||
set(value) {
|
val finishedFindingCharacters: ReadOnlyBooleanProperty = internalFinishedFindingCharacters
|
||||||
_isFindingWordsContaining.value = value
|
val finishedFindingSentences: ReadOnlyBooleanProperty = internalFinishedFindingSentences
|
||||||
}
|
|
||||||
|
|
||||||
var isFindingCharacters: Boolean
|
private val coroutineScope = MainScope()
|
||||||
get() = _isFindingCharacters.value
|
|
||||||
set(value) {
|
|
||||||
_isFindingCharacters.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var isFindingSentences: Boolean
|
fun copyHeadwordOfSelectedEntry() {
|
||||||
get() = _isFindingSentences.value
|
ClipboardHelper.copyString(internalSelectedEntry.value.traditional)
|
||||||
set(value) {
|
}
|
||||||
_isFindingSentences.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var finishedFindingWordsBeginning: Boolean
|
fun copyPronunciationOfSelectedEntry() {
|
||||||
get() = _finishedFindingWordsBeginning.value
|
ClipboardHelper.copyString(internalSelectedEntry.value.pinyinWithToneMarks)
|
||||||
set(value) {
|
}
|
||||||
_finishedFindingWordsBeginning.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var finishedFindingWordsContaining: Boolean
|
fun undoSelection() {
|
||||||
get() = _finishedFindingWordsContaining.value
|
undoManager.undo()
|
||||||
set(value) {
|
}
|
||||||
_finishedFindingWordsContaining.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var finishedFindingCharacters: Boolean
|
fun redoSelection() {
|
||||||
get() = _finishedFindingCharacters.value
|
undoManager.redo()
|
||||||
set(value) {
|
}
|
||||||
_finishedFindingCharacters.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var finishedFindingSentences: Boolean
|
fun search(query: String, searchMode: SearchMode) {
|
||||||
get() = _finishedFindingSentences.value
|
coroutineScope.launch {
|
||||||
set(value) {
|
internalIsSearching.value = true
|
||||||
_finishedFindingSentences.value = value
|
internalSearchResults.setAll(dictionary.search(query, searchMode))
|
||||||
|
internalIsSearching.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun selectedEntryProperty(): ObjectProperty<DictionaryEntry?> = _selectedEntry
|
fun findWordsBeginning() {
|
||||||
fun isSearchingProperty(): BooleanProperty = _isSearching
|
coroutineScope.launch {
|
||||||
fun isFindingWordsBeginningProperty(): BooleanProperty = _isFindingWordsBeginning
|
internalIsFindingWordsBeginning.value = true
|
||||||
fun isFindingWordsContainingProperty(): BooleanProperty = _isFindingWordsContaining
|
internalWordsBeginning.setAll(
|
||||||
fun isFindingCharactersProperty(): BooleanProperty = _isFindingCharacters
|
dictionary
|
||||||
fun isFindingSentencesProperty(): BooleanProperty = _isFindingSentences
|
.findWordsBeginningWith(internalSelectedEntry.value)
|
||||||
fun finishedFindingWordsBeginning(): BooleanProperty = _finishedFindingWordsBeginning
|
)
|
||||||
fun finishedFindingWordsContaining(): BooleanProperty = _finishedFindingWordsContaining
|
internalIsFindingWordsBeginning.value = false
|
||||||
fun finishedFindingCharacters(): BooleanProperty = _finishedFindingCharacters
|
internalFinishedFindingWordsBeginning.value = true
|
||||||
fun finishedFindingSentences(): BooleanProperty = _finishedFindingSentences
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findWordsContaining() {
|
||||||
|
coroutineScope.launch {
|
||||||
|
internalIsFindingWordsContaining.value = true
|
||||||
|
internalWordsContaining.setAll(
|
||||||
|
dictionary
|
||||||
|
.findWordsContaining(internalSelectedEntry.value)
|
||||||
|
)
|
||||||
|
internalIsFindingWordsContaining.value = false
|
||||||
|
internalFinishedFindingWordsContaining.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findCharacters() {
|
||||||
|
coroutineScope.launch {
|
||||||
|
internalIsFindingCharacters.value = true
|
||||||
|
internalCharacters.setAll(
|
||||||
|
dictionary
|
||||||
|
.findCharactersOf(internalSelectedEntry.value)
|
||||||
|
)
|
||||||
|
internalIsFindingCharacters.value = false
|
||||||
|
internalFinishedFindingCharacters.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findSentences() {
|
||||||
|
coroutineScope.launch {
|
||||||
|
internalIsFindingSentences.value = true
|
||||||
|
internalSentences.setAll(
|
||||||
|
dictionary
|
||||||
|
.findExampleSentencesFor(internalSelectedEntry.value)
|
||||||
|
)
|
||||||
|
internalIsFindingSentences.value = false
|
||||||
|
internalFinishedFindingSentences.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun selectEntry(entry: DictionaryEntry) {
|
||||||
|
undoManager.execute(object : Command {
|
||||||
|
private val previouslySelectedEntry = internalSelectedEntry.value
|
||||||
|
|
||||||
|
override fun execute() {
|
||||||
|
select(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun undo() {
|
||||||
|
if (previouslySelectedEntry == null) return
|
||||||
|
|
||||||
|
select(previouslySelectedEntry)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun select(entry: DictionaryEntry) {
|
||||||
|
internalFinishedFindingCharacters.value = false
|
||||||
|
internalFinishedFindingWordsBeginning.value = false
|
||||||
|
internalFinishedFindingWordsContaining.value = false
|
||||||
|
internalFinishedFindingSentences.value = false
|
||||||
|
|
||||||
|
internalSelectedEntry.value = entry
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,10 @@ class WillowApplication : Application() {
|
|||||||
}
|
}
|
||||||
val dictionary = SqliteDictionary(connection)
|
val dictionary = SqliteDictionary(connection)
|
||||||
val undoManager = UndoManager()
|
val undoManager = UndoManager()
|
||||||
val model = Model(undoManager)
|
val model = Model(
|
||||||
val interactor = Interactor(model, dictionary)
|
dictionary,
|
||||||
|
undoManager
|
||||||
|
)
|
||||||
val config = Config()
|
val config = Config()
|
||||||
config.load()
|
config.load()
|
||||||
|
|
||||||
@ -55,10 +57,10 @@ class WillowApplication : Application() {
|
|||||||
fxmlLoader.controllerFactory = Callback { type ->
|
fxmlLoader.controllerFactory = Callback { type ->
|
||||||
when (type) {
|
when (type) {
|
||||||
MainController::class.java -> MainController(model)
|
MainController::class.java -> MainController(model)
|
||||||
MenuController::class.java -> MenuController(model, interactor, config)
|
MenuController::class.java -> MenuController(model, config)
|
||||||
DetailsController::class.java -> DetailsController(model, interactor, config, hostServices)
|
DetailsController::class.java -> DetailsController(model, config, hostServices)
|
||||||
SearchController::class.java -> SearchController(model, interactor)
|
SearchController::class.java -> SearchController(model)
|
||||||
SearchResultsController::class.java -> SearchResultsController(model, interactor, config, hostServices)
|
SearchResultsController::class.java -> SearchResultsController(model, config, hostServices)
|
||||||
else -> error("Trying to instantiate unknown controller type $type")
|
else -> error("Trying to instantiate unknown controller type $type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.marvinelsen.willow.domain
|
package com.marvinelsen.willow.domain
|
||||||
|
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
import com.marvinelsen.willow.domain.entities.DictionaryEntry
|
||||||
import com.marvinelsen.willow.domain.objects.Sentence
|
import com.marvinelsen.willow.domain.entities.Sentence
|
||||||
|
|
||||||
interface Dictionary {
|
interface Dictionary {
|
||||||
suspend fun search(query: String, searchMode: SearchMode): List<DictionaryEntry>
|
suspend fun search(query: String, searchMode: SearchMode): List<DictionaryEntry>
|
||||||
|
@ -8,8 +8,8 @@ import com.github.houbb.segment.support.segment.impl.Segments
|
|||||||
import com.github.houbb.segment.support.segment.mode.impl.SegmentModes
|
import com.github.houbb.segment.support.segment.mode.impl.SegmentModes
|
||||||
import com.github.houbb.segment.support.segment.result.impl.SegmentResultHandlers
|
import com.github.houbb.segment.support.segment.result.impl.SegmentResultHandlers
|
||||||
import com.github.houbb.segment.support.tagging.pos.tag.impl.SegmentPosTaggings
|
import com.github.houbb.segment.support.tagging.pos.tag.impl.SegmentPosTaggings
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
import com.marvinelsen.willow.domain.entities.DictionaryEntry
|
||||||
import com.marvinelsen.willow.domain.objects.Sentence
|
import com.marvinelsen.willow.domain.entities.Sentence
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -31,21 +31,21 @@ class SqliteDictionary(private val connection: Connection) : Dictionary {
|
|||||||
.posData(SegmentPosDatas.define())
|
.posData(SegmentPosDatas.define())
|
||||||
|
|
||||||
private val searchSimplifiedSql = """
|
private val searchSimplifiedSql = """
|
||||||
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions, tones
|
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions
|
||||||
FROM entry
|
FROM entry
|
||||||
WHERE simplified GLOB ?
|
WHERE simplified GLOB ?
|
||||||
ORDER BY character_count ASC
|
ORDER BY character_count ASC
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
private val searchTraditionalSql = """
|
private val searchTraditionalSql = """
|
||||||
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions, tones
|
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions
|
||||||
FROM entry
|
FROM entry
|
||||||
WHERE traditional GLOB ?
|
WHERE traditional GLOB ?
|
||||||
ORDER BY character_count ASC
|
ORDER BY character_count ASC
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
private val searchPinyinSql = """
|
private val searchPinyinSql = """
|
||||||
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions, tones
|
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions
|
||||||
FROM entry
|
FROM entry
|
||||||
WHERE searchable_pinyin GLOB ?
|
WHERE searchable_pinyin GLOB ?
|
||||||
OR searchable_pinyin_with_tone_numbers GLOB ?
|
OR searchable_pinyin_with_tone_numbers GLOB ?
|
||||||
@ -54,21 +54,21 @@ class SqliteDictionary(private val connection: Connection) : Dictionary {
|
|||||||
|
|
||||||
private val searchSegmentsSql = """
|
private val searchSegmentsSql = """
|
||||||
WITH cte(id, segment) AS (VALUES ?)
|
WITH cte(id, segment) AS (VALUES ?)
|
||||||
SELECT entry.traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions, tones
|
SELECT entry.traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions
|
||||||
FROM entry INNER JOIN cte
|
FROM entry INNER JOIN cte
|
||||||
ON cte.segment = entry.traditional OR cte.segment = entry.simplified
|
ON cte.segment = entry.traditional OR cte.segment = entry.simplified
|
||||||
ORDER BY cte.id
|
ORDER BY cte.id
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
private val findWordsBeginningSql = """
|
private val findWordsBeginningSql = """
|
||||||
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions, tones
|
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions
|
||||||
FROM entry
|
FROM entry
|
||||||
WHERE traditional GLOB ?
|
WHERE traditional GLOB ?
|
||||||
ORDER BY character_count ASC
|
ORDER BY character_count ASC
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
private val findWordsContainingSql = """
|
private val findWordsContainingSql = """
|
||||||
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions, tones
|
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions
|
||||||
FROM entry
|
FROM entry
|
||||||
WHERE traditional LIKE ?
|
WHERE traditional LIKE ?
|
||||||
ORDER BY character_count ASC
|
ORDER BY character_count ASC
|
||||||
@ -76,7 +76,7 @@ class SqliteDictionary(private val connection: Connection) : Dictionary {
|
|||||||
|
|
||||||
private val findCharactersSql = """
|
private val findCharactersSql = """
|
||||||
WITH cte(id, character, pinyin) AS (VALUES ?)
|
WITH cte(id, character, pinyin) AS (VALUES ?)
|
||||||
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions, tones
|
SELECT traditional, simplified, pinyin_with_tone_marks, pinyin_with_tone_numbers, zhuyin, cedict_definitions, cross_straits_definitions, moe_definitions
|
||||||
FROM entry INNER JOIN cte
|
FROM entry INNER JOIN cte
|
||||||
ON cte.character = entry.traditional
|
ON cte.character = entry.traditional
|
||||||
WHERE cte.pinyin = entry.pinyin_with_tone_numbers
|
WHERE cte.pinyin = entry.pinyin_with_tone_numbers
|
||||||
@ -214,7 +214,6 @@ private fun ResultSet.toDictionaryEntry() = DictionaryEntry(
|
|||||||
cedictDefinitions = Json.decodeFromString(this.getString(6)),
|
cedictDefinitions = Json.decodeFromString(this.getString(6)),
|
||||||
crossStraitsDefinitions = Json.decodeFromString(this.getString(7)),
|
crossStraitsDefinitions = Json.decodeFromString(this.getString(7)),
|
||||||
moedictDefinitions = Json.decodeFromString(this.getString(8)),
|
moedictDefinitions = Json.decodeFromString(this.getString(8)),
|
||||||
tones = Json.decodeFromString(this.getString(9)),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun ResultSet.toListOfDictionaryEntries() = buildList {
|
private fun ResultSet.toListOfDictionaryEntries() = buildList {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.marvinelsen.willow.domain.objects
|
package com.marvinelsen.willow.domain.entities
|
||||||
|
|
||||||
import com.marvinelsen.willow.domain.objects.definitions.CrossStraitsDefinition
|
import com.marvinelsen.willow.domain.entities.definitions.CrossStraitsDefinition
|
||||||
import com.marvinelsen.willow.domain.objects.definitions.MoedictDefinition
|
import com.marvinelsen.willow.domain.entities.definitions.MoedictDefinition
|
||||||
|
|
||||||
data class DictionaryEntry(
|
data class DictionaryEntry(
|
||||||
val traditional: String,
|
val traditional: String,
|
||||||
@ -12,5 +12,4 @@ data class DictionaryEntry(
|
|||||||
val cedictDefinitions: List<List<String>>,
|
val cedictDefinitions: List<List<String>>,
|
||||||
val crossStraitsDefinitions: List<CrossStraitsDefinition>,
|
val crossStraitsDefinitions: List<CrossStraitsDefinition>,
|
||||||
val moedictDefinitions: List<MoedictDefinition>,
|
val moedictDefinitions: List<MoedictDefinition>,
|
||||||
val tones: List<Int>,
|
|
||||||
)
|
)
|
@ -1,4 +1,4 @@
|
|||||||
package com.marvinelsen.willow.domain.objects
|
package com.marvinelsen.willow.domain.entities
|
||||||
|
|
||||||
data class Sentence(
|
data class Sentence(
|
||||||
val traditional: String,
|
val traditional: String,
|
@ -1,4 +1,4 @@
|
|||||||
package com.marvinelsen.willow.domain.objects.definitions
|
package com.marvinelsen.willow.domain.entities.definitions
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.marvinelsen.willow.domain.objects.definitions
|
package com.marvinelsen.willow.domain.entities.definitions
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
@ -2,8 +2,8 @@ package com.marvinelsen.willow.ui.cells
|
|||||||
|
|
||||||
import com.marvinelsen.willow.config.Config
|
import com.marvinelsen.willow.config.Config
|
||||||
import com.marvinelsen.willow.config.Pronunciation
|
import com.marvinelsen.willow.config.Pronunciation
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
import com.marvinelsen.willow.config.Script
|
||||||
import com.marvinelsen.willow.ui.components.TextFlowWithToneColors
|
import com.marvinelsen.willow.domain.entities.DictionaryEntry
|
||||||
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
|
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
|
||||||
import javafx.application.HostServices
|
import javafx.application.HostServices
|
||||||
import javafx.beans.binding.Bindings
|
import javafx.beans.binding.Bindings
|
||||||
@ -39,8 +39,8 @@ private class EntryCell(
|
|||||||
private val hostServices: HostServices,
|
private val hostServices: HostServices,
|
||||||
) : ListCell<DictionaryEntry?>() {
|
) : ListCell<DictionaryEntry?>() {
|
||||||
|
|
||||||
private val textFlowHeadword by lazy {
|
private val labelHeadword by lazy {
|
||||||
TextFlowWithToneColors(config).apply {
|
Label().apply {
|
||||||
styleClass.add("headword")
|
styleClass.add("headword")
|
||||||
styleProperty().bind(
|
styleProperty().bind(
|
||||||
Bindings.concat(
|
Bindings.concat(
|
||||||
@ -83,7 +83,7 @@ private class EntryCell(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val flowPane by lazy {
|
private val flowPane by lazy {
|
||||||
FlowPane(textFlowHeadword, labelPronunciation).apply {
|
FlowPane(labelHeadword, labelPronunciation).apply {
|
||||||
hgap = FLOW_PANE_HGAP
|
hgap = FLOW_PANE_HGAP
|
||||||
rowValignment = VPos.BASELINE
|
rowValignment = VPos.BASELINE
|
||||||
}
|
}
|
||||||
@ -105,8 +105,17 @@ private class EntryCell(
|
|||||||
graphic = null
|
graphic = null
|
||||||
contextMenu = null
|
contextMenu = null
|
||||||
} else {
|
} else {
|
||||||
textFlowHeadword.entry.value = entry
|
labelHeadword.textProperty().bind(
|
||||||
|
Bindings.createStringBinding(
|
||||||
|
{
|
||||||
|
when (config.script.value!!) {
|
||||||
|
Script.SIMPLIFIED -> entry.simplified
|
||||||
|
Script.TRADITIONAL -> entry.traditional
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config.script
|
||||||
|
)
|
||||||
|
)
|
||||||
labelPronunciation.textProperty().bind(
|
labelPronunciation.textProperty().bind(
|
||||||
Bindings.createStringBinding(
|
Bindings.createStringBinding(
|
||||||
{
|
{
|
||||||
@ -135,7 +144,6 @@ private class EntryCell(
|
|||||||
|
|
||||||
else -> error("No definition for entry")
|
else -> error("No definition for entry")
|
||||||
}
|
}
|
||||||
|
|
||||||
labelDefinition.text = definition
|
labelDefinition.text = definition
|
||||||
|
|
||||||
contextMenu = createContextMenuForEntry(entry, resources, hostServices)
|
contextMenu = createContextMenuForEntry(entry, resources, hostServices)
|
||||||
|
@ -2,7 +2,7 @@ package com.marvinelsen.willow.ui.cells
|
|||||||
|
|
||||||
import com.marvinelsen.willow.config.Config
|
import com.marvinelsen.willow.config.Config
|
||||||
import com.marvinelsen.willow.config.Script
|
import com.marvinelsen.willow.config.Script
|
||||||
import com.marvinelsen.willow.domain.objects.Sentence
|
import com.marvinelsen.willow.domain.entities.Sentence
|
||||||
import com.marvinelsen.willow.ui.util.createContextMenuForSentence
|
import com.marvinelsen.willow.ui.util.createContextMenuForSentence
|
||||||
import javafx.application.HostServices
|
import javafx.application.HostServices
|
||||||
import javafx.beans.binding.Bindings
|
import javafx.beans.binding.Bindings
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
package com.marvinelsen.willow.ui.components
|
|
||||||
|
|
||||||
import com.marvinelsen.willow.config.Config
|
|
||||||
import com.marvinelsen.willow.config.Script
|
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
|
||||||
import javafx.scene.paint.Color
|
|
||||||
import javafx.scene.text.Text
|
|
||||||
import javafx.scene.text.TextFlow
|
|
||||||
|
|
||||||
class TextFlowWithToneColors(private val config: Config) : TextFlow() {
|
|
||||||
init {
|
|
||||||
config.script.addListener { _, _, newValue ->
|
|
||||||
updateTextFlow(newValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val entry = SimpleObjectProperty<DictionaryEntry?>().apply {
|
|
||||||
addListener { _, _, _ ->
|
|
||||||
updateTextFlow(config.script.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val invalidCharacterRegex = """[a-zA-Z0-9,.·\[\]{}()+]""".toRegex()
|
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
|
||||||
private fun updateTextFlow(script: Script) {
|
|
||||||
children.clear()
|
|
||||||
|
|
||||||
val headword = when (script) {
|
|
||||||
Script.SIMPLIFIED -> entry.value?.simplified
|
|
||||||
Script.TRADITIONAL -> entry.value?.traditional
|
|
||||||
} ?: return
|
|
||||||
|
|
||||||
var index = 0
|
|
||||||
for (char in headword) {
|
|
||||||
val text = Text(char.toString())
|
|
||||||
|
|
||||||
val color = if (invalidCharacterRegex.matches(char.toString())) {
|
|
||||||
Color.BLACK
|
|
||||||
} else {
|
|
||||||
when (entry.value?.tones?.getOrNull(index++)) {
|
|
||||||
1 -> Color.RED
|
|
||||||
2 -> Color.GREEN
|
|
||||||
3 -> Color.BLUE
|
|
||||||
4 -> Color.PURPLE
|
|
||||||
5 -> Color.DARKGRAY
|
|
||||||
else -> Color.BLACK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
text.fill = color
|
|
||||||
children.add(text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +1,11 @@
|
|||||||
package com.marvinelsen.willow.ui.controllers
|
package com.marvinelsen.willow.ui.controllers
|
||||||
|
|
||||||
import com.marvinelsen.willow.Interactor
|
|
||||||
import com.marvinelsen.willow.Model
|
import com.marvinelsen.willow.Model
|
||||||
import com.marvinelsen.willow.config.Config
|
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.domain.objects.DictionaryEntry
|
import com.marvinelsen.willow.domain.entities.DictionaryEntry
|
||||||
import com.marvinelsen.willow.domain.objects.Sentence
|
import com.marvinelsen.willow.domain.entities.Sentence
|
||||||
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.cells.SentenceCellFactory
|
||||||
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
|
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
|
||||||
@ -35,7 +34,6 @@ import java.util.ResourceBundle
|
|||||||
@Suppress("UnusedPrivateMember", "TooManyFunctions")
|
@Suppress("UnusedPrivateMember", "TooManyFunctions")
|
||||||
class DetailsController(
|
class DetailsController(
|
||||||
private val model: Model,
|
private val model: Model,
|
||||||
private val interactor: Interactor,
|
|
||||||
private val config: Config,
|
private val config: Config,
|
||||||
private val hostServices: HostServices,
|
private val hostServices: HostServices,
|
||||||
) {
|
) {
|
||||||
@ -114,13 +112,14 @@ class DetailsController(
|
|||||||
textProperty().bind(
|
textProperty().bind(
|
||||||
Bindings.createStringBinding(
|
Bindings.createStringBinding(
|
||||||
{
|
{
|
||||||
|
val selectedEntry = model.selectedEntry.value
|
||||||
when (config.script.value!!) {
|
when (config.script.value!!) {
|
||||||
Script.SIMPLIFIED -> model.selectedEntry?.simplified
|
Script.SIMPLIFIED -> selectedEntry?.simplified
|
||||||
Script.TRADITIONAL -> model.selectedEntry?.traditional
|
Script.TRADITIONAL -> selectedEntry?.traditional
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
config.script,
|
config.script,
|
||||||
model.selectedEntryProperty()
|
model.selectedEntry
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
styleProperty().bind(
|
styleProperty().bind(
|
||||||
@ -138,14 +137,15 @@ class DetailsController(
|
|||||||
textProperty().bind(
|
textProperty().bind(
|
||||||
Bindings.createStringBinding(
|
Bindings.createStringBinding(
|
||||||
{
|
{
|
||||||
|
val selectedEntry = model.selectedEntry.value
|
||||||
when (config.details.pronunciation.value!!) {
|
when (config.details.pronunciation.value!!) {
|
||||||
Pronunciation.PINYIN_WITH_TONE_MARKS -> model.selectedEntry?.pinyinWithToneMarks
|
Pronunciation.PINYIN_WITH_TONE_MARKS -> selectedEntry?.pinyinWithToneMarks
|
||||||
Pronunciation.PINYIN_WITH_TONE_NUMBERS -> model.selectedEntry?.pinyinWithToneNumbers
|
Pronunciation.PINYIN_WITH_TONE_NUMBERS -> selectedEntry?.pinyinWithToneNumbers
|
||||||
Pronunciation.ZHUYIN -> model.selectedEntry?.zhuyin
|
Pronunciation.ZHUYIN -> selectedEntry?.zhuyin
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
config.details.pronunciation,
|
config.details.pronunciation,
|
||||||
model.selectedEntryProperty()
|
model.selectedEntry
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
styleProperty().bind(
|
styleProperty().bind(
|
||||||
@ -160,16 +160,16 @@ class DetailsController(
|
|||||||
|
|
||||||
private fun initializeTabPaneDetails() {
|
private fun initializeTabPaneDetails() {
|
||||||
tabPaneDetails.apply {
|
tabPaneDetails.apply {
|
||||||
disableProperty().bind(Bindings.isNull(model.selectedEntryProperty()))
|
disableProperty().bind(Bindings.isNull(model.selectedEntry))
|
||||||
|
|
||||||
selectionModel.selectedItemProperty().addListener { _, _, selectedTab ->
|
selectionModel.selectedItemProperty().addListener { _, _, selectedTab ->
|
||||||
if (model.selectedEntry == null) return@addListener
|
if (model.selectedEntry.value == null) return@addListener
|
||||||
|
|
||||||
lazyUpdateTabContent(selectedTab.id)
|
lazyUpdateTabContent(selectedTab.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model.selectedEntryProperty().addListener { _, _, newEntry ->
|
model.selectedEntry.addListener { _, _, newEntry ->
|
||||||
if (newEntry == null) return@addListener
|
if (newEntry == null) return@addListener
|
||||||
|
|
||||||
tabPaneDetails.selectionModel.select(0)
|
tabPaneDetails.selectionModel.select(0)
|
||||||
@ -178,9 +178,9 @@ class DetailsController(
|
|||||||
tabCharacters.disableProperty().bind(
|
tabCharacters.disableProperty().bind(
|
||||||
Bindings.createBooleanBinding(
|
Bindings.createBooleanBinding(
|
||||||
{
|
{
|
||||||
(model.selectedEntry?.traditional?.length ?: 0) < 2
|
(model.selectedEntry.value?.traditional?.length ?: 0) < 2
|
||||||
},
|
},
|
||||||
model.selectedEntryProperty()
|
model.selectedEntry
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -190,12 +190,12 @@ class DetailsController(
|
|||||||
cellFactory = SentenceCellFactory(resources, config, hostServices)
|
cellFactory = SentenceCellFactory(resources, config, hostServices)
|
||||||
items = model.sentences
|
items = model.sentences
|
||||||
|
|
||||||
disableProperty().bind(Bindings.or(model.isFindingSentencesProperty(), Bindings.isEmpty(model.sentences)))
|
disableProperty().bind(Bindings.or(model.isFindingSentences, Bindings.isEmpty(model.sentences)))
|
||||||
}
|
}
|
||||||
progressIndicatorSentences.visibleProperty().bind(model.isFindingSentencesProperty())
|
progressIndicatorSentences.visibleProperty().bind(model.isFindingSentences)
|
||||||
labelNoSentencesFound
|
labelNoSentencesFound
|
||||||
.visibleProperty()
|
.visibleProperty()
|
||||||
.bind(Bindings.and(Bindings.isEmpty(model.sentences), Bindings.not(model.isFindingSentencesProperty())))
|
.bind(Bindings.and(Bindings.isEmpty(model.sentences), Bindings.not(model.isFindingSentences)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeListViewWordsContaining() {
|
private fun initializeListViewWordsContaining() {
|
||||||
@ -203,24 +203,17 @@ class DetailsController(
|
|||||||
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
|
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
|
||||||
items = model.wordsContaining
|
items = model.wordsContaining
|
||||||
|
|
||||||
disableProperty().bind(
|
disableProperty().bind(Bindings.or(model.isFindingWordsContaining, Bindings.isEmpty(model.wordsContaining)))
|
||||||
Bindings.or(model.isFindingWordsContainingProperty(), Bindings.isEmpty(model.wordsContaining))
|
|
||||||
)
|
|
||||||
|
|
||||||
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
|
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
|
||||||
if (newEntry == null) return@addListener
|
if (newEntry == null) return@addListener
|
||||||
interactor.deepDive(newEntry)
|
model.selectEntry(newEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progressIndicatorWordsContaining.visibleProperty().bind(model.isFindingWordsContainingProperty())
|
progressIndicatorWordsContaining.visibleProperty().bind(model.isFindingWordsContaining)
|
||||||
labelNoWordsContainingFound
|
labelNoWordsContainingFound
|
||||||
.visibleProperty()
|
.visibleProperty()
|
||||||
.bind(
|
.bind(Bindings.and(Bindings.isEmpty(model.wordsContaining), Bindings.not(model.isFindingWordsContaining)))
|
||||||
Bindings.and(
|
|
||||||
Bindings.isEmpty(model.wordsContaining),
|
|
||||||
Bindings.not(model.isFindingWordsContainingProperty())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeListViewWordsBeginning() {
|
private fun initializeListViewWordsBeginning() {
|
||||||
@ -228,24 +221,17 @@ class DetailsController(
|
|||||||
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
|
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
|
||||||
items = model.wordsBeginning
|
items = model.wordsBeginning
|
||||||
|
|
||||||
disableProperty().bind(
|
disableProperty().bind(Bindings.or(model.isFindingWordsBeginning, Bindings.isEmpty(model.wordsBeginning)))
|
||||||
Bindings.or(model.isFindingWordsBeginningProperty(), Bindings.isEmpty(model.wordsBeginning))
|
|
||||||
)
|
|
||||||
|
|
||||||
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
|
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
|
||||||
if (newEntry == null) return@addListener
|
if (newEntry == null) return@addListener
|
||||||
interactor.deepDive(newEntry)
|
model.selectEntry(newEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progressIndicatorWordsBeginning.visibleProperty().bind(model.isFindingWordsBeginningProperty())
|
progressIndicatorWordsBeginning.visibleProperty().bind(model.isFindingWordsBeginning)
|
||||||
labelNoWordsBeginningFound
|
labelNoWordsBeginningFound
|
||||||
.visibleProperty()
|
.visibleProperty()
|
||||||
.bind(
|
.bind(Bindings.and(Bindings.isEmpty(model.wordsBeginning), Bindings.not(model.isFindingWordsBeginning)))
|
||||||
Bindings.and(
|
|
||||||
Bindings.isEmpty(model.wordsBeginning),
|
|
||||||
Bindings.not(model.isFindingWordsBeginningProperty())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeListViewCharacters() {
|
private fun initializeListViewCharacters() {
|
||||||
@ -253,17 +239,17 @@ class DetailsController(
|
|||||||
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
|
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
|
||||||
items = model.characters
|
items = model.characters
|
||||||
|
|
||||||
disableProperty().bind(Bindings.or(model.isFindingCharactersProperty(), Bindings.isEmpty(model.characters)))
|
disableProperty().bind(Bindings.or(model.isFindingCharacters, Bindings.isEmpty(model.characters)))
|
||||||
|
|
||||||
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
|
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
|
||||||
if (newEntry == null) return@addListener
|
if (newEntry == null) return@addListener
|
||||||
interactor.deepDive(newEntry)
|
model.selectEntry(newEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progressIndicatorCharacters.visibleProperty().bind(model.isFindingCharactersProperty())
|
progressIndicatorCharacters.visibleProperty().bind(model.isFindingCharacters)
|
||||||
labelNoCharactersFound
|
labelNoCharactersFound
|
||||||
.visibleProperty()
|
.visibleProperty()
|
||||||
.bind(Bindings.and(Bindings.isEmpty(model.characters), Bindings.not(model.isFindingCharactersProperty())))
|
.bind(Bindings.and(Bindings.isEmpty(model.characters), Bindings.not(model.isFindingCharacters)))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeWebViewDefinition() {
|
private fun initializeWebViewDefinition() {
|
||||||
@ -271,7 +257,7 @@ class DetailsController(
|
|||||||
engine.userStyleSheetLocation = this::class.java.getResource("/css/definitions.css")!!.toExternalForm()
|
engine.userStyleSheetLocation = this::class.java.getResource("/css/definitions.css")!!.toExternalForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
model.selectedEntryProperty().addListener { _, _, newEntry ->
|
model.selectedEntry.addListener { _, _, newEntry ->
|
||||||
if (newEntry == null) return@addListener
|
if (newEntry == null) return@addListener
|
||||||
|
|
||||||
webViewDefinition.engine.loadContent(createDefinitionHtml(newEntry))
|
webViewDefinition.engine.loadContent(createDefinitionHtml(newEntry))
|
||||||
@ -280,9 +266,9 @@ class DetailsController(
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private fun headerOnContextMenuRequested(contextMenuEvent: ContextMenuEvent) {
|
private fun headerOnContextMenuRequested(contextMenuEvent: ContextMenuEvent) {
|
||||||
if (model.selectedEntry == null) return
|
if (model.selectedEntry.value == null) return
|
||||||
|
|
||||||
createContextMenuForEntry(model.selectedEntry!!, resources, hostServices).show(
|
createContextMenuForEntry(model.selectedEntry.value, resources, hostServices).show(
|
||||||
flowPaneHeader.scene.window,
|
flowPaneHeader.scene.window,
|
||||||
contextMenuEvent.screenX,
|
contextMenuEvent.screenX,
|
||||||
contextMenuEvent.screenY
|
contextMenuEvent.screenY
|
||||||
@ -293,24 +279,24 @@ class DetailsController(
|
|||||||
private fun lazyUpdateTabContent(selectedTabId: String?) {
|
private fun lazyUpdateTabContent(selectedTabId: String?) {
|
||||||
when (selectedTabId) {
|
when (selectedTabId) {
|
||||||
"tabWords" -> {
|
"tabWords" -> {
|
||||||
if (!model.finishedFindingWordsContaining) {
|
if (!model.finishedFindingWordsContaining.value) {
|
||||||
interactor.findWordsContaining()
|
model.findWordsContaining()
|
||||||
}
|
}
|
||||||
if (!model.finishedFindingWordsBeginning) {
|
if (!model.finishedFindingWordsBeginning.value) {
|
||||||
interactor.findWordsBeginning()
|
model.findWordsBeginning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"tabCharacters" -> {
|
"tabCharacters" -> {
|
||||||
if (model.finishedFindingCharacters) return
|
if (model.finishedFindingCharacters.value) return
|
||||||
|
|
||||||
interactor.findCharacters()
|
model.findCharacters()
|
||||||
}
|
}
|
||||||
|
|
||||||
"tabSentences" -> {
|
"tabSentences" -> {
|
||||||
if (model.finishedFindingSentences) return
|
if (model.finishedFindingSentences.value) return
|
||||||
|
|
||||||
interactor.findSentences()
|
model.findSentences()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.marvinelsen.willow.ui.controllers
|
package com.marvinelsen.willow.ui.controllers
|
||||||
|
|
||||||
import com.marvinelsen.willow.Interactor
|
|
||||||
import com.marvinelsen.willow.Model
|
import com.marvinelsen.willow.Model
|
||||||
import com.marvinelsen.willow.config.Config
|
import com.marvinelsen.willow.config.Config
|
||||||
import com.marvinelsen.willow.ui.dialogs.PreferencesDialog
|
import com.marvinelsen.willow.ui.dialogs.PreferencesDialog
|
||||||
@ -12,7 +11,7 @@ import javafx.scene.control.MenuItem
|
|||||||
import java.util.ResourceBundle
|
import java.util.ResourceBundle
|
||||||
|
|
||||||
@Suppress("UnusedPrivateMember")
|
@Suppress("UnusedPrivateMember")
|
||||||
class MenuController(private val model: Model, private val interactor: Interactor, private val config: Config) {
|
class MenuController(private val model: Model, private val config: Config) {
|
||||||
@FXML
|
@FXML
|
||||||
private lateinit var resources: ResourceBundle
|
private lateinit var resources: ResourceBundle
|
||||||
|
|
||||||
@ -27,8 +26,8 @@ class MenuController(private val model: Model, private val interactor: Interacto
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
menuItemCopyPronunciation.disableProperty().bind(Bindings.isNull(model.selectedEntryProperty()))
|
menuItemCopyPronunciation.disableProperty().bind(Bindings.isNull(model.selectedEntry))
|
||||||
menuItemCopyHeadword.disableProperty().bind(Bindings.isNull(model.selectedEntryProperty()))
|
menuItemCopyHeadword.disableProperty().bind(Bindings.isNull(model.selectedEntry))
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@ -48,11 +47,11 @@ class MenuController(private val model: Model, private val interactor: Interacto
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private fun onMenuItemCopyPronunciationAction() {
|
private fun onMenuItemCopyPronunciationAction() {
|
||||||
interactor.copyPronunciationOfSelectedEntry()
|
model.copyPronunciationOfSelectedEntry()
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private fun onMenuItemCopyHeadwordAction() {
|
private fun onMenuItemCopyHeadwordAction() {
|
||||||
interactor.copyHeadwordOfSelectedEntry()
|
model.copyHeadwordOfSelectedEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.marvinelsen.willow.ui.controllers
|
package com.marvinelsen.willow.ui.controllers
|
||||||
|
|
||||||
import com.marvinelsen.willow.Interactor
|
|
||||||
import com.marvinelsen.willow.Model
|
import com.marvinelsen.willow.Model
|
||||||
import com.marvinelsen.willow.domain.SearchMode
|
import com.marvinelsen.willow.domain.SearchMode
|
||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
@ -8,7 +7,7 @@ import javafx.scene.control.Button
|
|||||||
import javafx.scene.control.TextField
|
import javafx.scene.control.TextField
|
||||||
import javafx.scene.control.ToggleGroup
|
import javafx.scene.control.ToggleGroup
|
||||||
|
|
||||||
class SearchController(private val model: Model, private val interactor: Interactor) {
|
class SearchController(private val model: Model) {
|
||||||
@FXML
|
@FXML
|
||||||
private lateinit var buttonUndo: Button
|
private lateinit var buttonUndo: Button
|
||||||
|
|
||||||
@ -39,14 +38,14 @@ class SearchController(private val model: Model, private val interactor: Interac
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
interactor.search(searchQuery, searchMode)
|
model.search(searchQuery, searchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onButtonRedoAction() {
|
fun onButtonRedoAction() {
|
||||||
interactor.redoSelection()
|
model.redoSelection()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onButtonUndoAction() {
|
fun onButtonUndoAction() {
|
||||||
interactor.undoSelection()
|
model.undoSelection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package com.marvinelsen.willow.ui.controllers
|
package com.marvinelsen.willow.ui.controllers
|
||||||
|
|
||||||
import com.marvinelsen.willow.Interactor
|
|
||||||
import com.marvinelsen.willow.Model
|
import com.marvinelsen.willow.Model
|
||||||
import com.marvinelsen.willow.config.Config
|
import com.marvinelsen.willow.config.Config
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
import com.marvinelsen.willow.domain.entities.DictionaryEntry
|
||||||
import com.marvinelsen.willow.ui.cells.DictionaryEntryCellFactory
|
import com.marvinelsen.willow.ui.cells.DictionaryEntryCellFactory
|
||||||
import javafx.application.HostServices
|
import javafx.application.HostServices
|
||||||
import javafx.beans.binding.Bindings
|
import javafx.beans.binding.Bindings
|
||||||
@ -15,7 +14,6 @@ import java.util.ResourceBundle
|
|||||||
|
|
||||||
class SearchResultsController(
|
class SearchResultsController(
|
||||||
private val model: Model,
|
private val model: Model,
|
||||||
private val interactor: Interactor,
|
|
||||||
private val config: Config,
|
private val config: Config,
|
||||||
private val hostServices: HostServices,
|
private val hostServices: HostServices,
|
||||||
) {
|
) {
|
||||||
@ -40,18 +38,18 @@ class SearchResultsController(
|
|||||||
listViewSearchResults.items = model.searchResults
|
listViewSearchResults.items = model.searchResults
|
||||||
listViewSearchResults
|
listViewSearchResults
|
||||||
.disableProperty()
|
.disableProperty()
|
||||||
.bind(Bindings.or(model.isSearchingProperty(), Bindings.isEmpty(model.searchResults)))
|
.bind(Bindings.or(model.isSearching, Bindings.isEmpty(model.searchResults)))
|
||||||
|
|
||||||
progressIndicatorEntries.visibleProperty().bind(model.isSearchingProperty())
|
progressIndicatorEntries.visibleProperty().bind(model.isSearching)
|
||||||
labelNoEntriesFound
|
labelNoEntriesFound
|
||||||
.visibleProperty()
|
.visibleProperty()
|
||||||
.bind(Bindings.and(Bindings.isEmpty(model.searchResults), Bindings.not(model.isSearchingProperty())))
|
.bind(Bindings.and(Bindings.isEmpty(model.searchResults), Bindings.not(model.isSearching)))
|
||||||
|
|
||||||
listViewSearchResults.selectionModel.selectedItemProperty().addListener { _, _, newValue: DictionaryEntry? ->
|
listViewSearchResults.selectionModel.selectedItemProperty().addListener { _, _, newValue: DictionaryEntry? ->
|
||||||
if (newValue == null) {
|
if (newValue == null) {
|
||||||
return@addListener
|
return@addListener
|
||||||
}
|
}
|
||||||
interactor.normalSelect(newValue)
|
model.selectEntry(newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,13 @@ class PreferencesDialogController(private val config: Config) {
|
|||||||
@FXML
|
@FXML
|
||||||
private lateinit var spinnerDefinitionFontSizeSearchResults: Spinner<Int>
|
private lateinit var spinnerDefinitionFontSizeSearchResults: Spinner<Int>
|
||||||
|
|
||||||
|
private val entryHeadwordFontSizeObjectProperty = config.details.headwordFontSize.asObject()
|
||||||
|
private val entryPronunciationFontSizeObjectProperty = config.details.pronunciationFontSize.asObject()
|
||||||
|
|
||||||
|
private val searchResultHeadwordFontSizeObjectProperty = config.searchResults.headwordFontSize.asObject()
|
||||||
|
private val searchResultPronunciationFontSizeObjectProperty = config.searchResults.pronunciationFontSize.asObject()
|
||||||
|
private val searchResultDefinitionFontSizeObjectProperty = config.searchResults.definitionFontSize.asObject()
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
comboBoxLocale.items.addAll(
|
comboBoxLocale.items.addAll(
|
||||||
@ -75,42 +82,27 @@ class PreferencesDialogController(private val config: Config) {
|
|||||||
|
|
||||||
with(spinnerHeadwordFontSizeDetails) {
|
with(spinnerHeadwordFontSizeDetails) {
|
||||||
editor.textFormatter = FontSizeTextFormatter()
|
editor.textFormatter = FontSizeTextFormatter()
|
||||||
valueFactory.value = config.details.headwordFontSize.value
|
valueFactory.valueProperty().bindBidirectional(entryHeadwordFontSizeObjectProperty)
|
||||||
valueProperty().addListener { _, _, newValue ->
|
|
||||||
config.details.headwordFontSize.value = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
with(spinnerPronunciationFontSizeDetails) {
|
with(spinnerPronunciationFontSizeDetails) {
|
||||||
editor.textFormatter = FontSizeTextFormatter()
|
editor.textFormatter = FontSizeTextFormatter()
|
||||||
valueFactory.value = config.details.pronunciationFontSize.value
|
valueFactory.valueProperty().bindBidirectional(entryPronunciationFontSizeObjectProperty)
|
||||||
valueProperty().addListener { _, _, newValue ->
|
|
||||||
config.details.pronunciationFontSize.value = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
with(spinnerHeadwordFontSizeSearchResults) {
|
with(spinnerHeadwordFontSizeSearchResults) {
|
||||||
editor.textFormatter = FontSizeTextFormatter()
|
editor.textFormatter = FontSizeTextFormatter()
|
||||||
valueFactory.value = config.searchResults.headwordFontSize.value
|
valueFactory.valueProperty().bindBidirectional(searchResultHeadwordFontSizeObjectProperty)
|
||||||
valueProperty().addListener { _, _, newValue ->
|
|
||||||
config.searchResults.headwordFontSize.value = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
with(spinnerPronunciationFontSizeSearchResults) {
|
with(spinnerPronunciationFontSizeSearchResults) {
|
||||||
editor.textFormatter = FontSizeTextFormatter()
|
editor.textFormatter = FontSizeTextFormatter()
|
||||||
valueFactory.value = config.searchResults.pronunciationFontSize.value
|
valueFactory.valueProperty().bindBidirectional(searchResultPronunciationFontSizeObjectProperty)
|
||||||
valueProperty().addListener { _, _, newValue ->
|
|
||||||
config.searchResults.pronunciationFontSize.value = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
with(spinnerDefinitionFontSizeSearchResults) {
|
with(spinnerDefinitionFontSizeSearchResults) {
|
||||||
editor.textFormatter = FontSizeTextFormatter()
|
editor.textFormatter = FontSizeTextFormatter()
|
||||||
valueFactory.value = config.searchResults.definitionFontSize.value
|
valueFactory.valueProperty().bindBidirectional(searchResultDefinitionFontSizeObjectProperty)
|
||||||
valueProperty().addListener { _, _, newValue ->
|
|
||||||
config.searchResults.definitionFontSize.value = newValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ class UndoManager {
|
|||||||
|
|
||||||
undoStack.push(command).execute()
|
undoStack.push(command).execute()
|
||||||
|
|
||||||
canUndoProperty.value = !undoStack.isEmpty()
|
canUndoProperty.value = undoStack.size > 1
|
||||||
canRedoProperty.value = false
|
canRedoProperty.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ class UndoManager {
|
|||||||
|
|
||||||
redoStack.push(undoStack.pop()).undo()
|
redoStack.push(undoStack.pop()).undo()
|
||||||
|
|
||||||
canUndoProperty.value = !undoStack.isEmpty()
|
canUndoProperty.value = undoStack.size > 1
|
||||||
canRedoProperty.value = true
|
canRedoProperty.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,11 +36,4 @@ class UndoManager {
|
|||||||
canUndoProperty.value = true
|
canUndoProperty.value = true
|
||||||
canRedoProperty.value = !redoStack.isEmpty()
|
canRedoProperty.value = !redoStack.isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
|
||||||
undoStack.clear()
|
|
||||||
redoStack.clear()
|
|
||||||
canUndoProperty.value = false
|
|
||||||
canRedoProperty.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.marvinelsen.willow.ui.util
|
package com.marvinelsen.willow.ui.util
|
||||||
|
|
||||||
import com.marvinelsen.willow.domain.objects.DictionaryEntry
|
import com.marvinelsen.willow.domain.entities.DictionaryEntry
|
||||||
import com.marvinelsen.willow.domain.objects.Sentence
|
import com.marvinelsen.willow.domain.entities.Sentence
|
||||||
import javafx.application.HostServices
|
import javafx.application.HostServices
|
||||||
import javafx.event.EventHandler
|
import javafx.event.EventHandler
|
||||||
import javafx.scene.control.ContextMenu
|
import javafx.scene.control.ContextMenu
|
||||||
|
Loading…
x
Reference in New Issue
Block a user