From f0a47cf843c7d7a87e8175b2b488791e4fc9c172 Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Thu, 26 May 2022 09:53:43 +0800 Subject: [PATCH 01/28] Fix Typo; Pre-Release 2.3.3 --- CHANGELOG | 2 + .../kotlin/ink/meodinger/lpfx/Controller.kt | 63 +++++++++---------- src/main/kotlin/ink/meodinger/lpfx/State.kt | 18 +++--- src/main/kotlin/ink/meodinger/lpfx/View.kt | 2 +- .../lpfx/component/tools/FormatChecker.kt | 1 + .../lpfx/component/tools/OnlineDict.kt | 36 +++++------ 6 files changed, 58 insertions(+), 64 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b8270cf..8e0c46f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,8 @@ TODO: Fix - 修正了当换页后选中的Label索引值与上一页选中的Label索引值相同时无法输入翻译文本的问题; + - 修正了Label有时候会放歪的问题; + - 修正了框选Label后关闭文档会产生异常的问题; Add - 现在可以直接使用滚轮来缩放图片(需要设置); - 现在可以在启动时直接打开上次文件(需要设置); diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index d86e758..33bf019 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -104,7 +104,7 @@ class Controller(private val state: State) { } } - private var accumulator: Long = 16 * 60 * 60 * ONE_SECOND + private var accumulator: Long = 16 * 60 * 60 * ONE_SECOND // Shift to 1970/01/02 00:00 GMT+8 private val accumulatorFormatter = SimpleDateFormat("HH:mm:ss") private val accumulatorManager = TimerTaskManager(0, ONE_SECOND) { if (state.isOpened) { @@ -202,12 +202,7 @@ class Controller(private val state: State) { Logger.info("Controller initialized", "Controller") // Display default image - cLabelPane.isVisible = false - Platform.runLater { - // re-locate after the initial rendering - cLabelPane.moveToCenter() - cLabelPane.isVisible = true - } + cLabelPane.moveToCenter() } /** @@ -1122,38 +1117,38 @@ class Controller(private val state: State) { val version = fetchLatestSync() if (version != Version.V0) Logger.info("Got latest version: $version (current $V)", "Controller") - if (version > V) Platform.runLater { - val suppressNoticeButtonType = ButtonType(I18N["update.dialog.suppress"], ButtonBar.ButtonData.OK_DONE) - - val dialog = Dialog() - dialog.initOwner(this@Controller.state.stage) - dialog.title = I18N["update.dialog.title"] - dialog.graphic = ImageView(IMAGE_INFO.resizeByRadius(GENERAL_ICON_RADIUS)) - dialog.dialogPane.buttonTypes.addAll(suppressNoticeButtonType, ButtonType.CLOSE) - dialog.dialogPane.withContent(VBox()) { - add(Label(String.format(I18N["update.dialog.content.s"], version))) - add(Separator()) { - padding = Insets(8.0, 0.0, 8.0, 0.0) - } - add(Hyperlink(I18N["update.dialog.link"])) { - padding = Insets(0.0) - setOnAction { this@Controller.state.application.hostServices.showDocument(release) } + Platform.runLater { + if (version > V) { + val suppressNoticeButtonType = ButtonType(I18N["update.dialog.suppress"], ButtonBar.ButtonData.OK_DONE) + + val dialog = Dialog() + dialog.initOwner(this@Controller.state.stage) + dialog.title = I18N["update.dialog.title"] + dialog.graphic = ImageView(IMAGE_INFO.resizeByRadius(GENERAL_ICON_RADIUS)) + dialog.dialogPane.buttonTypes.addAll(suppressNoticeButtonType, ButtonType.CLOSE) + dialog.dialogPane.withContent(VBox()) { + add(Label(String.format(I18N["update.dialog.content.s"], version))) + add(Separator()) { + padding = Insets(8.0, 0.0, 8.0, 0.0) + } + add(Hyperlink(I18N["update.dialog.link"])) { + padding = Insets(0.0) + setOnAction { this@Controller.state.application.hostServices.showDocument(release) } + } } - } - val suppressButton = dialog.dialogPane.lookupButton(suppressNoticeButtonType) - ButtonBar.setButtonUniformSize(suppressButton, false) + val suppressButton = dialog.dialogPane.lookupButton(suppressNoticeButtonType) + ButtonBar.setButtonUniformSize(suppressButton, false) - dialog.showAndWait().ifPresent { type -> - if (type == suppressNoticeButtonType) { - Preference.lastUpdateNotice = time - Logger.info("Check suppressed, next notice time is ${time + delay}", - "Controller" - ) + dialog.showAndWait().ifPresent { type -> + if (type == suppressNoticeButtonType) { + Preference.lastUpdateNotice = time + Logger.info("Check suppressed, next notice time is ${time + delay}", "Controller") + } } + } else if (showWhenUpdated) { + showInfo(this@Controller.state.stage, I18N["update.info.updated"]) } - } else if (showWhenUpdated) Platform.runLater { - showInfo(this@Controller.state.stage, I18N["update.info.updated"]) } }() } diff --git a/src/main/kotlin/ink/meodinger/lpfx/State.kt b/src/main/kotlin/ink/meodinger/lpfx/State.kt index c2d88b5..13e27ec 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/State.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/State.kt @@ -172,21 +172,21 @@ class State { private val undoStack: Stack = ArrayStack() private val redoStack: Stack = ArrayStack() - private val canUndoProperty: BooleanProperty = SimpleBooleanProperty(false) + private val undoableProperty: BooleanProperty = SimpleBooleanProperty(false) /** * Whether undo is available */ - fun undoableProperty(): ReadOnlyBooleanProperty = canUndoProperty + fun undoableProperty(): ReadOnlyBooleanProperty = undoableProperty /** * @see undoableProperty */ - val isUndoable: Boolean by canUndoProperty + val isUndoable: Boolean by undoableProperty private val redoableProperty: BooleanProperty = SimpleBooleanProperty(false) /** * Whether redo is available */ - fun canRedoProperty(): ReadOnlyBooleanProperty = redoableProperty + fun redoableProperty(): ReadOnlyBooleanProperty = redoableProperty /** * @see redoableProperty */ @@ -201,7 +201,7 @@ class State { Logger.info("Action committed", "State") isChanged = true - canUndoProperty.set(true) + undoableProperty.set(true) redoableProperty.set(false) } @@ -214,7 +214,7 @@ class State { redoStack.push(undoStack.pop().apply(Action::revert)) Logger.info("Action reverted", "State") - canUndoProperty.set(!undoStack.isEmpty()) + undoableProperty.set(!undoStack.isEmpty()) redoableProperty.set(true) } @@ -227,18 +227,16 @@ class State { undoStack.push(redoStack.pop().apply(Action::commit)) Logger.info("Action re-committed", "State") - canUndoProperty.set(true) + undoableProperty.set(true) redoableProperty.set(!redoStack.isEmpty()) } // endregion /** - * Reset the entire worksapce, be ready to open another translation. + * Reset the entire workspace, be ready to open another translation. */ fun reset() { - if (!isOpened) return - controller.reset() undoStack.empty() diff --git a/src/main/kotlin/ink/meodinger/lpfx/View.kt b/src/main/kotlin/ink/meodinger/lpfx/View.kt index 0fbbfb2..fd5c4d4 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/View.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/View.kt @@ -243,7 +243,7 @@ class View(private val state: State) : BorderPane() { } item(I18N["m.redo"]) { does { state.redo() } - disableProperty().bind(!state.canRedoProperty()) + disableProperty().bind(!state.redoableProperty()) accelerator = KeyCodeCombination(KeyCode.Z, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN) } separator() diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/tools/FormatChecker.kt b/src/main/kotlin/ink/meodinger/lpfx/component/tools/FormatChecker.kt index 5e4cba0..00ee039 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/tools/FormatChecker.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/tools/FormatChecker.kt @@ -123,6 +123,7 @@ class FormatChecker(private val state: State) : Stage() { // Select Range state.view.cTransArea.selectRange(match.range.first, match.range.last + 1) }) + closeOnEscape() } diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/tools/OnlineDict.kt b/src/main/kotlin/ink/meodinger/lpfx/component/tools/OnlineDict.kt index 6c5eaf4..f1b41e4 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/tools/OnlineDict.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/tools/OnlineDict.kt @@ -110,13 +110,23 @@ class OnlineDict : Stage() { transState = TransState.values()[(transState.ordinal + 1) % TransState.values().size] } - if (Config.enableIMEAssistance) addEventHandler(MouseEvent.MOUSE_CLICKED) { - if (it.isDoubleClick && getCurrentLanguage().startsWith(JA)) { - setImeConversionMode( - getCurrentWindow(), - ImeSentenceMode.AUTOMATIC, - ImeConversionMode.JA_HIRAGANA - ) + if (Config.enableIMEAssistance) { + focusedProperty().addListener(onNew { + // We do not set the IMEConversion mode here because switch language need time. + if (it) { + oriLang = getCurrentLanguage() + // Focus gain will take place after the rendering, so it's safe to set by sync. + AvailableLanguages.firstOrNull { lang -> lang.startsWith(JA) }?.apply(::setCurrentLanguage) + } else { + // If set immediately after lose focus will cause focus on other stages fail. + // Use runLater to set language after the rendering. + Platform.runLater { setCurrentLanguage(oriLang) } + } + }) + addEventHandler(MouseEvent.MOUSE_CLICKED) { + if (it.isDoubleClick && getCurrentLanguage().startsWith(JA)) { + setImeConversionMode(getCurrentWindow(), ImeSentenceMode.AUTOMATIC, ImeConversionMode.JA_HIRAGANA) + } } } } @@ -132,18 +142,6 @@ class OnlineDict : Stage() { } }) - if (Config.enableIMEAssistance) focusedProperty().addListener(onNew { - // We do not set the IMEConversion mode here because switch language need time. - if (it) { - oriLang = getCurrentLanguage() - // Focus gain will take place after the rendering, so it's safe to set by sync. - AvailableLanguages.firstOrNull { lang -> lang.startsWith(JA) }?.apply(::setCurrentLanguage) - } else { - // If set immediately after lose focus will cause focus on other stages fail. - // Use runLater to set language after the rendering. - Platform.runLater { setCurrentLanguage(oriLang) } - } - }) closeOnEscape() } From 4318f9b673a4a4cba6f89acd91045b6e283c45e5 Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 11:59:46 +0800 Subject: [PATCH 02/28] Fix file save format issue --- src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 33bf019..684379c 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -942,7 +942,7 @@ class Controller(private val state: State) { } // Use temp if overwrite - val exportDest = if (overwrite) File.createTempFile(file.path, "temp").apply(File::deleteOnExit) else file + val exportDest = if (overwrite) File.createTempFile("LPFX", file.extension).apply(File::deleteOnExit) else file // Export try { From 97c4c8d69c85e82c0e56f3e661c88666535599d7 Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 12:06:28 +0800 Subject: [PATCH 03/28] Add gitignore; Fix save file format --- .gitignore | 1 + script/jpackage/LabelPlusFXDict.lnk | Bin 0 -> 1266 bytes src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 script/jpackage/LabelPlusFXDict.lnk diff --git a/.gitignore b/.gitignore index 2be1234..99faba9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ !/script/jlink/*.bat /script/jpackage/* !/script/jpackage/build.* +!/script/jpackage/LabelPlusFXDict.lnk lpfx.iml lpfx.ipr diff --git a/script/jpackage/LabelPlusFXDict.lnk b/script/jpackage/LabelPlusFXDict.lnk new file mode 100644 index 0000000000000000000000000000000000000000..4d2445b5ef726955ade2aedff0e34dcf7e8d0c14 GIT binary patch literal 1266 zcma)5SxA&o6#m9cTq4IbGbx=G!4}6YACd%VH0QzGM$}{!&H1&dSzN|Oqen|3qXL7V zP0EtQ0v|$(6n(0PAd`|QECeGVQxSR)pZdc-lMU7D^~Zg`JP|sW2@{tqzOR-God8!5{NO?fGuwtKy&#J$=l*n>Yvg zj;fNM$AeN>;eZ8BxY0yyB+9)}-*3~x)Y{}y?5Qch@pa;M4oTdAHE}P#n1BhbjOT&^ zJ5s^ph(d|1Y(1r@J3)sUyG5_GDBgNS`>NQa)@%44&J)X|`dI2b_YpOWXMvt^TL`Ha zC?s|fLZ_@p2pI)L6d^SZ2Y>L_a$RMKjIN00)fUaG72zNf(ZD~L$aFfjjcPQq866Xw zk&9}aW^x-7*w9S-36yzD(jkGLg|yc2gq6fP=-)^>_8{&rT8e0M(kG5F*U}{#BeIz* zSEWzSh&F!G!e*c=j_X%K+702}oi`Fa?N^aEkfrZ`UU+*zY*hqX?<(Ue!>%|jR!5!E zn4mb$w*qr_gO*}af8;#MZPQM+^_7?Ho7N91Ghw~A0vm2za!vfp{+oRBN_90ecCx9! zG@CT|#ege0J&U8^-A%Q7Pf>4?#IeMFVtwLth({LERT7-2B_VE=Fol|vq}i#G=|COj zMjViU98U>JnzRr%FrO2xeZ1gT)p38OPhLc@I7m`qYyG6Y3$&d+p#<+C$GfYST@H^% zlv`vk0uJwx8M_I85hOH!0y-<>n?o*KuN0j)ZWSSu_+s-WhQ) a5(`Vm7UxFx82ZMt1KzwHSb2$J1^xgH76x(v literal 0 HcmV?d00001 diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 684379c..cf9ec8a 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -942,7 +942,7 @@ class Controller(private val state: State) { } // Use temp if overwrite - val exportDest = if (overwrite) File.createTempFile("LPFX", file.extension).apply(File::deleteOnExit) else file + val exportDest = if (overwrite) File.createTempFile("LPFX", ".${file.extension}").apply(File::deleteOnExit) else file // Export try { From ccf60f9962adae0f16ac85e2c9ce1b21e2bc55f4 Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 12:17:27 +0800 Subject: [PATCH 04/28] Add icon on Dict --- src/main/kotlin/ink/meodinger/lpfx/LabelPlusFXDict.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/ink/meodinger/lpfx/LabelPlusFXDict.kt b/src/main/kotlin/ink/meodinger/lpfx/LabelPlusFXDict.kt index c8a5017..9f6b950 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/LabelPlusFXDict.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/LabelPlusFXDict.kt @@ -30,6 +30,7 @@ class LabelPlusFXDict: Application() { showException(primaryStage, e) } // Set up the Stage + primaryStage.icons.add(ICON) primaryStage.title = "LPFX Dictionary (Standalone)" primaryStage.scene = OnlineDict().scene primaryStage.width = 400.0 From 5f187dd8d71898b3fc57c3bd237081f52984b889 Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 13:10:09 +0800 Subject: [PATCH 05/28] Fix empty String issue with number pattern; Add Fixme for ObservableKeySet --- src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 6 ++++-- .../ink/meodinger/lpfx/util/property/Extension.kt | 12 ++++++++++-- .../kotlin/ink/meodinger/lpfx/util/string/Number.kt | 8 ++++++-- .../ink/meodinger/lpfx/util/string/CStringKtTest.kt | 4 ++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index cf9ec8a..b7972c2 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -428,8 +428,10 @@ class Controller(private val state: State) { cPicBox.itemsProperty().bind(picNamesBinding) cPicBox.indexProperty().addListener(onNew { if (state.isOpened) { - // PicBox index should never be -1 (value should never be null) - state.currentPicName = state.transFile.sortedPicNames[it] + if (it != NOT_FOUND) { + // PicBox index should never be -1 except when removing a picture + state.currentPicName = state.transFile.sortedPicNames[it] + } } else { // Closed, do nothing. Let State set current-pic-name to empty string } diff --git a/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt b/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt index 7897dea..8e812fe 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt @@ -9,6 +9,8 @@ import javafx.collections.* * Have fun with my code! */ +// FIXME: JFX's UnmodifiableSet use WeakListener which may cause change cannot go to the next layer. +// Write my own to replace it /** * Return a ObservableSet that reflect the keys and their changes of the ObservableMap @@ -40,7 +42,10 @@ fun ObservableMap.observableKeySet(): ObservableSet { fun ObservableSet.observableSorted(sorter: (Set) -> List): ObservableList { val list = FXCollections.observableArrayList(sorter(this)) - addListener(SetChangeListener { list.setAll(sorter(it.set)) }) + addListener(SetChangeListener { + // Sort the set whenever it changes + list.setAll(sorter(it.set)) + }) return FXCollections.unmodifiableObservableList(list) } @@ -51,7 +56,10 @@ fun ObservableSet.observableSorted(sorter: (Set) -> List): Observab fun ObservableList.observableSorted(sorter: (List) -> List): ObservableList { val list = FXCollections.observableArrayList(sorter(this)) - addListener(ListChangeListener { list.setAll(sorter(it.list)) }) + addListener(ListChangeListener { + // Sort the list whenever it changes + list.setAll(sorter(it.list)) + }) return FXCollections.unmodifiableObservableList(list) } diff --git a/src/main/kotlin/ink/meodinger/lpfx/util/string/Number.kt b/src/main/kotlin/ink/meodinger/lpfx/util/string/Number.kt index e5bae50..4ca2995 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/util/string/Number.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/util/string/Number.kt @@ -11,6 +11,8 @@ package ink.meodinger.lpfx.util.string * Is the String a mathematical natural number */ fun String.isMathematicalNatural(): Boolean { + if (isEmpty()) return false + val iterator = this.toCharArray().iterator() while (iterator.hasNext()) if (iterator.nextChar() !in '0'..'9') @@ -23,9 +25,10 @@ fun String.isMathematicalNatural(): Boolean { * Is the String a mathematical integer */ fun String.isMathematicalInteger(): Boolean { + if (isEmpty()) return false + val chars = this.toCharArray() val isNegative = chars[0] == '-' - return if (isNegative) substring(1).isMathematicalNatural() else isMathematicalNatural() } @@ -33,8 +36,9 @@ fun String.isMathematicalInteger(): Boolean { * Is the String a mathematical decimal */ fun String.isMathematicalDecimal(): Boolean { - val chars = this.toCharArray() + if (isEmpty()) return false + val chars = this.toCharArray() var index = 0 val isNegative = chars[index] == '-' if (isNegative) index++ diff --git a/src/test/kotlin/ink/meodinger/lpfx/util/string/CStringKtTest.kt b/src/test/kotlin/ink/meodinger/lpfx/util/string/CStringKtTest.kt index ad6ffa7..efb28a6 100644 --- a/src/test/kotlin/ink/meodinger/lpfx/util/string/CStringKtTest.kt +++ b/src/test/kotlin/ink/meodinger/lpfx/util/string/CStringKtTest.kt @@ -44,6 +44,8 @@ class CStringKtTest { @Test fun isMathNaturalTest() { + assertFalse("".isMathematicalNatural()) + assertTrue("123".isMathematicalNatural()) assertFalse("-123".isMathematicalNatural()) @@ -70,6 +72,7 @@ class CStringKtTest { @Test fun isMathIntegerTest() { + assertFalse("".isMathematicalInteger()) assertTrue("123".isMathematicalInteger()) assertTrue("-123".isMathematicalInteger()) @@ -96,6 +99,7 @@ class CStringKtTest { @Test fun isMathDecimalTest() { + assertFalse("".isMathematicalDecimal()) assertTrue("123".isMathematicalDecimal()) assertTrue("-123".isMathematicalDecimal()) From de7bfc8180319dff3775a4042000a54c9d1b2d2e Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 17:00:49 +0800 Subject: [PATCH 06/28] Fix Observable Extension Functions --- .../meodinger/lpfx/util/property/Extension.kt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt b/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt index 8e812fe..375b1cb 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt @@ -9,12 +9,10 @@ import javafx.collections.* * Have fun with my code! */ -// FIXME: JFX's UnmodifiableSet use WeakListener which may cause change cannot go to the next layer. -// Write my own to replace it /** - * Return a ObservableSet that reflect the keys and their changes of the ObservableMap - * @return An unmodifiable ObservableSet + * Return a ObservableSet that reflect the keys and their changes of the ObservableMap. + * @return An ObservableSet that **MUTABLE** but you should better **NOT** change it. */ fun ObservableMap.observableKeySet(): ObservableSet { val set = FXCollections.observableSet(HashSet(keys)) @@ -32,12 +30,13 @@ fun ObservableMap.observableKeySet(): ObservableSet { } }) - return FXCollections.unmodifiableObservableSet(set) + // It's a compromise with the WeakListener attached to UnmodifiableSet which often offline. + return set } /** * Return a ObservableList that reflect the sorted elements and their changes of the ObservableSet - * @return An unmodifiable ObservableList + * @return An ObservableList that **MUTABLE** but you should better **NOT** change it. */ fun ObservableSet.observableSorted(sorter: (Set) -> List): ObservableList { val list = FXCollections.observableArrayList(sorter(this)) @@ -47,11 +46,12 @@ fun ObservableSet.observableSorted(sorter: (Set) -> List): Observab list.setAll(sorter(it.set)) }) - return FXCollections.unmodifiableObservableList(list) + // It's a compromise with the WeakListener attached to UnmodifiableList which often offline. + return list } /** * Return a ObservableList that reflect the sorted elements and their changes of the ObservableList - * @return An unmodifiable ObservableList + * @return An ObservableList that **MUTABLE** but you should better **NOT** change it. */ fun ObservableList.observableSorted(sorter: (List) -> List): ObservableList { val list = FXCollections.observableArrayList(sorter(this)) @@ -61,5 +61,6 @@ fun ObservableList.observableSorted(sorter: (List) -> List): Observ list.setAll(sorter(it.list)) }) - return FXCollections.unmodifiableObservableList(list) + // It's a compromise with the WeakListener attached to UnmodifiableList which often offline. + return list } From fa695bc51d380df0f7b09a507548492436c291ae Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 17:38:12 +0800 Subject: [PATCH 07/28] Add TransGroup::index --- .../ink/meodinger/lpfx/action/GroupAction.kt | 11 +++-- .../ink/meodinger/lpfx/type/TransFile.kt | 41 ++++++++++++++++--- .../ink/meodinger/lpfx/type/TransGroup.kt | 30 ++++++++++++++ .../meodinger/lpfx/util/property/Extension.kt | 9 ++++ 4 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt b/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt index 618d631..1878614 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt @@ -58,21 +58,20 @@ class GroupAction( throw IllegalArgumentException(String.format(I18N["exception.action.group_repeated.s"], transGroup.name)) state.transFile.groupListObservable.add(groupId, transGroup) - for (labels in state.transFile.transMapObservable.values) for (label in labels) if (label.groupId >= groupId) label.groupId++ + @Suppress("DEPRECATION") state.transFile.installGroup(transGroup) Logger.info("Added TransGroup: $transGroup", "Action") } private fun removeTransGroup(transGroup: TransGroup) { - val groupId = state.transFile.getGroupIdByName(transGroup.name) - if (state.transFile.isGroupStillInUse(groupId)) + if (state.transFile.isGroupStillInUse(transGroup.index)) throw IllegalArgumentException(String.format(I18N["exception.action.group_still_in_use.s"], transGroup.name)) + @Suppress("DEPRECATION") state.transFile.disposeGroup(transGroup) for (labels in state.transFile.transMapObservable.values) for (label in labels) - if (label.groupId >= groupId) label.groupId-- - - state.transFile.groupListObservable.removeAt(groupId) + if (label.groupId >= transGroup.index) label.groupId-- + state.transFile.groupListObservable.removeAt(transGroup.index) Logger.info("Removed TransGroup: $transGroup", "Action") } diff --git a/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt b/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt index 5409450..bad0e5b 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt @@ -91,11 +91,15 @@ class TransFile @JsonCreator constructor( // endregion // region Properties + // Only internal use to avoid accidentally invoking their `set` methods - // Note1: version is immutable - // Note2: all backing list/map/set should be mutable - // Note3: groups' properties' changes will be listened - // Note4: transMap use LinkedHashMap to preserve key order when export. + // Note1: version is immutable. + // Note2: all backing list/map/set should be mutable. + // Note3: groups' properties' changes will be listened. + // Note4: transMap use LinkedHashMap to preserve the key order when exported, + // and for a more general constructor with `Map` instead of `MutableMap`. + // LinkedHashMap doesn't slower than an ordinary HashMap, please see + // https://stackoverflow.com/a/17708526/15969136. private val versionProperty: ReadOnlyListProperty = SimpleListProperty(FXCollections.observableList(version)) private val commentProperty: StringProperty = SimpleStringProperty(comment) @@ -108,12 +112,13 @@ class TransFile @JsonCreator constructor( // region Accessible Fields - // Following properties provide JSON getters + // Following properties provide JSON getters/setters val version: List by versionProperty var comment: String by commentProperty val groupList: List by groupListProperty val transMap: Map> by transMapProperty + // Only use these when you want an ObservableValue or modify properties (except sorted-pic-names) val groupListObservable: ObservableList by groupListProperty val transMapObservable: ObservableMap> by transMapProperty val sortedPicNamesObservable: ObservableList by sortedPicNamesProperty @@ -128,6 +133,8 @@ class TransFile @JsonCreator constructor( @Suppress("DEPRECATION") for (labels in transMap.values) for (label in labels) installLabel(label) } + // TODO: Use Group-Name + // region TransGroup fun getGroupIdByName(name: String): Int { @@ -137,9 +144,28 @@ class TransFile @JsonCreator constructor( return transMap.values.flatten().any { label -> label.groupId == groupId } } + /** + * Install the color-property of TransLabel based on this TransFile + */ + @Deprecated(level = DeprecationLevel.WARNING, message = "Only in Action") + fun installGroup(transGroup: TransGroup) { + @Suppress("DEPRECATION") + TransGroup.installIndex(transGroup, groupListProperty.observableIndexOf(transGroup)) + } + /** + * Dispose the color-property of TransLabel + */ + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated(level = DeprecationLevel.WARNING, message = "Only in Action") + fun disposeGroup(transGroup: TransGroup) { + @Suppress("DEPRECATION") + TransGroup.disposeIndex(transGroup) + } + // endregion // region TransLabel + /** * Install the color-property of TransLabel based on this TransFile */ @@ -151,6 +177,7 @@ class TransFile @JsonCreator constructor( /** * Dispose the color-property of TransLabel */ + @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated(level = DeprecationLevel.WARNING, message = "Only in Action") fun disposeLabel(transLabel: TransLabel) { @Suppress("DEPRECATION") @@ -161,9 +188,13 @@ class TransFile @JsonCreator constructor( // region Getters + @Deprecated(level = DeprecationLevel.WARNING, message = "Use name") fun getTransGroup(groupId: Int): TransGroup { return groupListObservable[groupId] } + fun getTransGroup(groupName: String): TransGroup { + return groupListObservable.first { it.name == groupName } + } fun getTransList(picName: String): List { return transMapObservable[picName]!! } diff --git a/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt b/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt index 86fd827..a46684a 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt @@ -1,6 +1,7 @@ package ink.meodinger.lpfx.type import ink.meodinger.lpfx.I18N +import ink.meodinger.lpfx.NOT_FOUND import ink.meodinger.lpfx.get import ink.meodinger.lpfx.util.color.isColorHex import ink.meodinger.lpfx.util.property.getValue @@ -8,6 +9,7 @@ import ink.meodinger.lpfx.util.property.readonly import ink.meodinger.lpfx.util.property.transform import com.fasterxml.jackson.annotation.* +import javafx.beans.binding.IntegerExpression import javafx.beans.property.* import javafx.scene.paint.Color @@ -28,6 +30,23 @@ class TransGroup @JsonCreator constructor( ) { companion object { private var ACC = 0 + + /** + * Bind TransLabel's ColorProperty, This function should only be called in TransFile + */ + @Deprecated(level = DeprecationLevel.WARNING, message = "Only in TransFile") + fun installIndex(transGroup: TransGroup, property: IntegerExpression) { + transGroup.indexProperty.bind(property) + } + + /** + * Unbind TransLabel's ColorProperty, This function should only be called in TransFile + */ + @Deprecated(level = DeprecationLevel.WARNING, message = "Only in TransFile") + fun disposeIndex(transGroup: TransGroup) { + transGroup.indexProperty.unbind() + } + } // region Properties @@ -56,6 +75,17 @@ class TransGroup @JsonCreator constructor( // region Additional + private val indexProperty: IntegerProperty = SimpleIntegerProperty(NOT_FOUND) + /** + * This property represents the group-id of this TransGroup + * if this TransGroup was installed by a TransFile, or NOT_FOUND. + */ + fun indexProperty(): ReadOnlyIntegerProperty = indexProperty + /** + * @see indexProperty + */ + val index: Int by indexProperty + private val colorProperty: ReadOnlyObjectProperty = colorHexProperty.transform(Color::web).readonly() /** * This property is transformed from [colorHexProperty] by `Color::web` diff --git a/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt b/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt index 375b1cb..0e339a2 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/util/property/Extension.kt @@ -1,5 +1,7 @@ package ink.meodinger.lpfx.util.property +import javafx.beans.binding.Bindings +import javafx.beans.binding.IntegerBinding import javafx.collections.* @@ -64,3 +66,10 @@ fun ObservableList.observableSorted(sorter: (List) -> List): Observ // It's a compromise with the WeakListener attached to UnmodifiableList which often offline. return list } + +/** + * Return a IntegerBinding that represents the index in the list of the given element + */ +fun ObservableList.observableIndexOf(element: E): IntegerBinding { + return Bindings.createIntegerBinding({ indexOf(element) }, this) +} From 1cff93931201f7577336e72cccc7ef7ee4ac964d Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 18:02:54 +0800 Subject: [PATCH 08/28] Use GroupName --- .../kotlin/ink/meodinger/lpfx/Controller.kt | 12 +++---- .../ink/meodinger/lpfx/action/GroupAction.kt | 2 +- .../ink/meodinger/lpfx/component/CTreeMenu.kt | 14 ++++----- .../ink/meodinger/lpfx/type/TransFile.kt | 31 ++++++++++--------- .../ink/meodinger/lpfx/type/TransGroup.kt | 24 +++++++------- .../ink/meodinger/lpfx/type/TransLabel.kt | 4 +-- 6 files changed, 44 insertions(+), 43 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index b7972c2..9ac3417 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -348,7 +348,7 @@ class Controller(private val state: State) { } WorkMode.LabelMode -> { val transLabel = state.transFile.getTransLabel(state.currentPicName, it.labelIndex) - val transGroup = state.transFile.getTransGroup(transLabel.groupId) + val transGroup = state.transFile.groupList[transLabel.groupId] cLabelPane.showText(transGroup.name, transGroup.color, it.displayX, it.displayY) } } @@ -382,7 +382,7 @@ class Controller(private val state: State) { WorkMode.LabelMode -> { if (state.currentGroupId == NOT_FOUND) return@handler - val transGroup = state.transFile.getTransGroup(state.currentGroupId) + val transGroup = state.transFile.groupList[state.currentGroupId] cLabelPane.showText(transGroup.name, transGroup.color, it.displayX, it.displayY) } } @@ -400,10 +400,10 @@ class Controller(private val state: State) { if (it != NOT_FOUND) { if (cTreeView.isFocused) { // if the change is result of CTreeView selection, add - cTreeView.selectGroup(state.transFile.getTransGroup(it).name, clear = false, scrollTo = false) + cTreeView.selectGroup(state.transFile.groupList[it].name, clear = false, scrollTo = false) } else { // if the change is result of GroupBar/Box selection, set - cTreeView.selectGroup(state.transFile.getTransGroup(it).name, clear = true, scrollTo = true) + cTreeView.selectGroup(state.transFile.groupList[it].name, clear = true, scrollTo = true) } } } else { @@ -620,7 +620,7 @@ class Controller(private val state: State) { // Try select val index = number - 1 if (state.viewMode == ViewMode.GroupMode) { - cTreeView.selectGroup(state.transFile.getTransGroup(index).name, clear = true, scrollTo = false) + cTreeView.selectGroup(state.transFile.groupList[index].name, clear = true, scrollTo = false) } else { state.currentGroupId = index } @@ -634,7 +634,7 @@ class Controller(private val state: State) { if (index in 0 until state.transFile.groupCount) { // Try select if (state.viewMode == ViewMode.GroupMode) { - cTreeView.selectGroup(state.transFile.getTransGroup(index).name, clear = true, scrollTo = false) + cTreeView.selectGroup(state.transFile.groupList[index].name, clear = true, scrollTo = false) } else { state.currentGroupId = index } diff --git a/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt b/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt index 1878614..cd1dbdf 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/action/GroupAction.kt @@ -65,7 +65,7 @@ class GroupAction( Logger.info("Added TransGroup: $transGroup", "Action") } private fun removeTransGroup(transGroup: TransGroup) { - if (state.transFile.isGroupStillInUse(transGroup.index)) + if (state.transFile.isGroupStillInUse(transGroup.name)) throw IllegalArgumentException(String.format(I18N["exception.action.group_still_in_use.s"], transGroup.name)) @Suppress("DEPRECATION") state.transFile.disposeGroup(transGroup) diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index 4f365e6..92d2ed2 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -117,7 +117,7 @@ class CTreeMenu( // do Action state.doAction(GroupAction( ActionType.CHANGE, state, - state.transFile.getTransGroup(state.transFile.getGroupIdByName(it.source as String)), + state.transFile.getTransGroup(it.source as String), newName = newName )) } @@ -128,7 +128,7 @@ class CTreeMenu( private val gChangeColorHandler = EventHandler { state.doAction(GroupAction( ActionType.CHANGE, state, - state.transFile.getTransGroup(state.transFile.getGroupIdByName(it.source as String)), + state.transFile.getTransGroup(it.source as String), newColorHex = (it.target as ColorPicker).value.toHexRGB() )) } @@ -142,7 +142,7 @@ class CTreeMenu( state.doAction(GroupAction( ActionType.REMOVE, state, - state.transFile.getTransGroup(state.transFile.getGroupIdByName(it.source as String)) + state.transFile.getTransGroup(it.source as String) )) // Select the first group if TransFile has @@ -163,14 +163,14 @@ class CTreeMenu( } val choice = dialog.showAndWait() if (!choice.isPresent) return@EventHandler - val newGroupId = state.transFile.getGroupIdByName(choice.get()) + val transGroup = state.transFile.getTransGroup(choice.get()) val labelActions = items.map { LabelAction( ActionType.CHANGE, state, state.currentPicName, state.transFile.getTransLabel(state.currentPicName, it.transLabel.index), - newGroupId = newGroupId + newGroupId = transGroup.index ) } val moveAction = FunctionAction( @@ -223,7 +223,7 @@ class CTreeMenu( val groupItem = selectedItems[0] as CTreeGroupItem gChangeColorPicker.value = groupItem.transGroup.color - gDeleteItem.isDisable = state.transFile.isGroupStillInUse(state.transFile.getGroupIdByName(groupItem.value)) + gDeleteItem.isDisable = state.transFile.isGroupStillInUse(groupItem.value) gRenameItem.setOnAction { gRenameHandler.handle(ActionEvent(groupItem.transGroup.name, gRenameItem)) } gChangeColorPicker.setOnAction { gChangeColorHandler.handle(ActionEvent(groupItem.transGroup.name, gChangeColorPicker)) } @@ -238,7 +238,7 @@ class CTreeMenu( // NOTE: we cannot change names here, so it is safe to store names val groupNames = selectedItems.map { (it as CTreeGroupItem).transGroup.name } - gDeleteItem.isDisable = groupNames.any { state.transFile.isGroupStillInUse(state.transFile.getGroupIdByName(it)) } + gDeleteItem.isDisable = groupNames.any { state.transFile.isGroupStillInUse(it) } gDeleteItem.setOnAction { groupNames.forEach { gDeleteHandler.handle(ActionEvent(it, gDeleteItem)) } } items.add(gDeleteItem) diff --git a/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt b/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt index bad0e5b..ac24c72 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/type/TransFile.kt @@ -16,7 +16,7 @@ import java.io.File */ /** - * A MEO Translation file + * A Translation file */ @JsonIncludeProperties("version", "comment", "groupList", "transMap") class TransFile @JsonCreator constructor( @@ -131,21 +131,23 @@ class TransFile @JsonCreator constructor( init { @Suppress("DEPRECATION") for (labels in transMap.values) for (label in labels) installLabel(label) + @Suppress("DEPRECATION") for (transGroup in groupList) installGroup(transGroup) } - // TODO: Use Group-Name - // region TransGroup - fun getGroupIdByName(name: String): Int { - return groupList.first { it.name == name }.let(groupList::indexOf) - } - fun isGroupStillInUse(groupId: Int): Boolean { + /** + * Whether a TransGroup is still in use + * @param groupName The target TransGroup's name + */ + fun isGroupStillInUse(groupName: String): Boolean { + val groupId = groupList.indexOfFirst { it.name == groupName } return transMap.values.flatten().any { label -> label.groupId == groupId } } /** - * Install the color-property of TransLabel based on this TransFile + * Install the color-property of TransLabel based on this TransFile. + * This should only be called within an Action. */ @Deprecated(level = DeprecationLevel.WARNING, message = "Only in Action") fun installGroup(transGroup: TransGroup) { @@ -153,7 +155,8 @@ class TransFile @JsonCreator constructor( TransGroup.installIndex(transGroup, groupListProperty.observableIndexOf(transGroup)) } /** - * Dispose the color-property of TransLabel + * Dispose the color-property of TransLabel. + * This should only be called within an Action. */ @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated(level = DeprecationLevel.WARNING, message = "Only in Action") @@ -167,7 +170,8 @@ class TransFile @JsonCreator constructor( // region TransLabel /** - * Install the color-property of TransLabel based on this TransFile + * Install the index-property of TransGroup based on this TransFile. + * This should only be called within an Action. */ @Deprecated(level = DeprecationLevel.WARNING, message = "Only in Action") fun installLabel(transLabel: TransLabel) { @@ -175,7 +179,8 @@ class TransFile @JsonCreator constructor( TransLabel.installColor(transLabel, groupListProperty.valueAt(transLabel.groupIdProperty()).transform(TransGroup::color)) } /** - * Dispose the color-property of TransLabel + * Dispose the index-property of TransGroup. + * This should only be called within an Action. */ @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated(level = DeprecationLevel.WARNING, message = "Only in Action") @@ -188,10 +193,6 @@ class TransFile @JsonCreator constructor( // region Getters - @Deprecated(level = DeprecationLevel.WARNING, message = "Use name") - fun getTransGroup(groupId: Int): TransGroup { - return groupListObservable[groupId] - } fun getTransGroup(groupName: String): TransGroup { return groupListObservable.first { it.name == groupName } } diff --git a/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt b/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt index a46684a..babe24f 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/type/TransGroup.kt @@ -32,7 +32,7 @@ class TransGroup @JsonCreator constructor( private var ACC = 0 /** - * Bind TransLabel's ColorProperty, This function should only be called in TransFile + * Bind TransGroup's index-property, This function should only be called in TransFile */ @Deprecated(level = DeprecationLevel.WARNING, message = "Only in TransFile") fun installIndex(transGroup: TransGroup, property: IntegerExpression) { @@ -40,7 +40,7 @@ class TransGroup @JsonCreator constructor( } /** - * Unbind TransLabel's ColorProperty, This function should only be called in TransFile + * Unbind TransGroup's index-property, This function should only be called in TransFile */ @Deprecated(level = DeprecationLevel.WARNING, message = "Only in TransFile") fun disposeIndex(transGroup: TransGroup) { @@ -75,6 +75,16 @@ class TransGroup @JsonCreator constructor( // region Additional + private val colorProperty: ReadOnlyObjectProperty = colorHexProperty.transform(Color::web).readonly() + /** + * This property is transformed from [colorHexProperty] by `Color::web` + */ + fun colorProperty(): ReadOnlyObjectProperty = colorProperty + /** + * @see colorProperty + */ + val color: Color by colorProperty + private val indexProperty: IntegerProperty = SimpleIntegerProperty(NOT_FOUND) /** * This property represents the group-id of this TransGroup @@ -86,16 +96,6 @@ class TransGroup @JsonCreator constructor( */ val index: Int by indexProperty - private val colorProperty: ReadOnlyObjectProperty = colorHexProperty.transform(Color::web).readonly() - /** - * This property is transformed from [colorHexProperty] by `Color::web` - */ - fun colorProperty(): ReadOnlyObjectProperty = colorProperty - /** - * @see colorProperty - */ - val color: Color by colorProperty - // endregion override fun toString(): String = "TransGroup(name=$name, color=$colorHex)" diff --git a/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt b/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt index 0a9d137..f33dc0a 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt @@ -33,7 +33,7 @@ class TransLabel @JsonCreator constructor( companion object { /** - * Bind TransLabel's ColorProperty, This function should only be called in TransFile + * Bind TransLabel's color-property, This function should only be called within a TransFile. */ @Deprecated(level = DeprecationLevel.WARNING, message = "Only in TransFile") fun installColor(transLabel: TransLabel, property: ObjectExpression) { @@ -41,7 +41,7 @@ class TransLabel @JsonCreator constructor( } /** - * Unbind TransLabel's ColorProperty, This function should only be called in TransFile + * Unbind TransLabel's color-property, This function should only be called within a TransFile. */ @Deprecated(level = DeprecationLevel.WARNING, message = "Only in TransFile") fun disposeColor(transLabel: TransLabel) { From 36d57d5e9d7a6b4a5dea1eaf682cb48001180c6f Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 18:20:39 +0800 Subject: [PATCH 09/28] Add NaN check for coordinate of TransLabel --- src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 2 +- src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 9ac3417..ea71fab 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -911,8 +911,8 @@ class Controller(private val state: State) { state.currentLabelIndex = labelIndex.takeIf { state.transFile.getTransList(state.currentPicName).any { l -> l.index == it } } ?: NOT_FOUND // Move to center - // FIXME: May throw NoSuchElementException if render not complete if (labelIndex != NOT_FOUND) { + // NotNow: May throw NoSuchElementException if render not complete cTreeView.selectLabel(labelIndex, clear = true, scrollTo = true) cLabelPane.moveToLabel(labelIndex) } diff --git a/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt b/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt index f33dc0a..874e567 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/type/TransLabel.kt @@ -77,7 +77,7 @@ class TransLabel @JsonCreator constructor( var x: Double get() = xProperty.get() set(value) { - if (value < 0 || value > 1) + if (!value.isNaN() && (value < 0 || value > 1)) throw IllegalArgumentException(String.format(I18N["exception.trans_label.x_invalid.d"], value)) xProperty.set(value) } @@ -87,7 +87,7 @@ class TransLabel @JsonCreator constructor( var y: Double get() = yProperty.get() set(value) { - if (value < 0 || value > 1) + if (!value.isNaN() && (value < 0 || value > 1)) throw IllegalArgumentException(String.format(I18N["exception.trans_label.y_invalid.d"], value)) yProperty.set(value) } From 220d865c393f859ba62d45b6b9e76c9a23fb2563 Mon Sep 17 00:00:00 2001 From: Meodinger Wang <54493746+Meodinger@users.noreply.github.com> Date: Fri, 27 May 2022 18:27:38 +0800 Subject: [PATCH 10/28] Release 2.3.3 --- CHANGELOG | 3 +++ pom.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 8e0c46f..379debc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,9 @@ Fix - 修正了当换页后选中的Label索引值与上一页选中的Label索引值相同时无法输入翻译文本的问题; - 修正了Label有时候会放歪的问题; - 修正了框选Label后关闭文档会产生异常的问题; + - 修正了保存文件格式不匹配的问题; + - 修正了无法编辑项目图片的问题; + - 修正了排序报错的问题; Add - 现在可以直接使用滚轮来缩放图片(需要设置); - 现在可以在启动时直接打开上次文件(需要设置); diff --git a/pom.xml b/pom.xml index 4e5229d..343aa79 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ ink.meodinger lpfx - 2.3.3-SNAPSHOT + 2.3.3 jar lpfx From f9c2382f0b756764884b49404f5ad6562fe43262 Mon Sep 17 00:00:00 2001 From: yeding Date: Mon, 20 Feb 2023 23:06:20 +0800 Subject: [PATCH 11/28] add a button to move the index of label fix a bug about the picture switch by keywordKeyboard shortcut --- pom.xml | 4 ++ .../kotlin/ink/meodinger/lpfx/Controller.kt | 2 +- .../ink/meodinger/lpfx/action/LabelAction.kt | 10 ++++- .../ink/meodinger/lpfx/component/CTreeMenu.kt | 40 +++++++++++++++++++ .../ink/meodinger/lpfx/Lang_zh_CN.properties | 8 +++- 5 files changed, 61 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 343aa79..f6577f0 100644 --- a/pom.xml +++ b/pom.xml @@ -118,6 +118,10 @@ org.apache.maven.plugins maven-compiler-plugin 3.8.1 + + 17 + 17 + org.apache.maven.plugins diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index ea71fab..22d62aa 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -656,7 +656,7 @@ class Controller(private val state: State) { KeyCode.RIGHT -> cPicBox.next() else -> return@handler } - + cLabelPane.fireEvent(keyEvent(it, code = KeyCode.DOWN, character = "", text = "")) it.consume() // Consume used event } cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) diff --git a/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt b/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt index 7153f24..a5b0bd7 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt @@ -50,7 +50,15 @@ class LabelAction( if (newLabelIndex != NOT_FOUND) { builder.append("@index: ${targetTransLabel.index.pad(2)} -> ${index.pad(2)}; ") - targetTransLabel.index = index + if (targetTransLabel.index == index) return + val list = state.transFile.transMapObservable[targetPicName] + ?: throw IllegalArgumentException(String.format(I18N["exception.action.picture_not_found.s"], targetPicName)) + if(index > targetTransLabel.index) { + for (label in list) if (label.index > targetTransLabel.index && label.index <= index) label.index-- + } else { + for (label in list) if (label.index >= index && label.index < targetTransLabel.index) label.index++ + } + targetTransLabel.index = index } if (newGroupId != NOT_FOUND) { builder.append("@groupId: ${targetTransLabel.groupId.pad(2)} -> ${groupId.pad(2)}; ") diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index 92d2ed2..a1dd3e7 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -9,6 +9,7 @@ import ink.meodinger.lpfx.type.TransGroup import ink.meodinger.lpfx.util.color.toHexRGB import ink.meodinger.lpfx.util.component.withContent import ink.meodinger.lpfx.component.dialog.showError +import ink.meodinger.lpfx.type.TransLabel import ink.meodinger.lpfx.util.doNothing import ink.meodinger.lpfx.util.property.transform @@ -194,6 +195,43 @@ class CTreeMenu( } private val lDeleteItem = MenuItem(I18N["context.delete_label"]) + private val lMoveToLabelHandler = EventHandler { event -> + @Suppress("UNCHECKED_CAST") val items = event.source as List + val item = items.get(0) + val labels = state.transFile.getTransList(state.currentPicName).map(TransLabel::index); +// val groups = state.transFile.groupList.map(TransGroup::name) +// +// val dialog = ChoiceDialog(groups[0], groups).apply { +// initOwner(state.stage) +// title = I18N["context.move_to.dialog.title"] +// contentText = +// if (items.size == 1) I18N["context.move_to.dialog.header"] +// else I18N["context.move_to.dialog.header.pl"] +// } + val dialog = ChoiceDialog(labels[0], labels).apply { + initOwner(state.stage) + title = I18N["context.move_to_label.dialog.title"] + contentText = I18N["context.move_to_label.dialog.header"] + } + val choice = dialog.showAndWait() + if (!choice.isPresent) return@EventHandler +// val transGroup = state.transFile.getTransGroup(choice.get()) + val labelAction= LabelAction( + ActionType.CHANGE, state, + state.currentPicName, + state.transFile.getTransLabel(state.currentPicName, item.transLabel.index), + newLabelIndex = choice.get() + ) + + val moveAction = FunctionAction( + { labelAction.commit(); state.controller.requestUpdateTree() }, + { labelAction.revert(); state.controller.requestUpdateTree() } + ) + state.doAction(moveAction) + } + + private val lMoveToLabelItem = MenuItem(I18N["context.move_to_label"]) + // endregion init { @@ -244,9 +282,11 @@ class CTreeMenu( items.add(gDeleteItem) } else if (rootCount == 0 && groupCount == 0 && labelCount > 0) { // label(s) + lMoveToLabelItem.setOnAction { lMoveToLabelHandler.handle(ActionEvent(selectedItems, lMoveToLabelItem)) } lMoveToItem.setOnAction { lMoveToHandler.handle(ActionEvent(selectedItems, lMoveToItem)) } lDeleteItem.setOnAction { lDeleteHandler.handle(ActionEvent(selectedItems, lDeleteItem)) } + items.add(lMoveToLabelItem) items.add(lMoveToItem) items.add(SeparatorMenuItem()) items.add(lDeleteItem) diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties index 911efa1..7536a08 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties @@ -77,11 +77,17 @@ context.rename_group.dialog.title = 重命名分组 context.rename_group.dialog.header = 请输入新的分组名称 context.delete_group = 删除 ## label(s) -context.move_to = 移动到… +context.move_to = 移动分组 context.move_to.dialog.title = 移动到其他分组 context.move_to.dialog.header = 请选择目标分组 context.move_to.dialog.header.pl = 请选择目标分组 context.delete_label = 删除 +context.move_to_label = 移动序号 +context.move_to_label.dialog.title = 移动到其它序号 +context.move_to_label.dialog.header = 请选择目标序号 + + + # mode mode.work.input = 输入模式 From 9f8c332f79890bfc247b1e98307a09d07619903e Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 5 Mar 2023 17:53:03 +0800 Subject: [PATCH 12/28] add i18n text --- src/main/resources/ink/meodinger/lpfx/Lang_en.properties | 3 +++ src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties index 1762517..511c039 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties @@ -81,6 +81,9 @@ context.move_to = Move To context.move_to.dialog.title = Move To Other Group context.move_to.dialog.header = Please choose the group you want to move the label to context.move_to.dialog.header.pl = Please choose the group you want to move these labels to +context.move_to_label = Move To Other Index +context.move_to_label.dialog.title = Please choose the Index you want to move the label to +context.move_to_label.dialog.header =Please choose the Index you want to move the label to context.delete_label = Delete # mode diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties index 7914a57..3eb8f01 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties @@ -81,6 +81,9 @@ context.move_to = 移動到… context.move_to.dialog.title = 移動到其他分組 context.move_to.dialog.header = 請選擇目標分組 context.move_to.dialog.header.pl = 請選擇目標分組 +context.move_to_label = 移動序號 +context.move_to_label.dialog.title = 移動到其他序號 +context.move_to_label.dialog.header = 请选择目标序號 context.delete_label = 删除 # mode From f1217a2ad82e6f41c8855d3f4734dcacf17a0b24 Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 5 Mar 2023 22:16:22 +0800 Subject: [PATCH 13/28] fix some bug and chang something --- CHANGELOG | 15 ++++ .../kotlin/ink/meodinger/lpfx/Controller.kt | 79 +++++++++++-------- .../ink/meodinger/lpfx/component/CTreeMenu.kt | 14 +--- .../ink/meodinger/lpfx/component/CTreeView.kt | 8 ++ 4 files changed, 71 insertions(+), 45 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 379debc..dcdef8a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,21 @@ TODO: - 备份文件上限(Next) - 保存specify(Next) +# 2.3.3.1 + +Fix + +- 尝试修复图片区数字快捷键报错 + +Add + +- 选中右键树状图中的Label支持移动序号 + +Change + +- 移动Label序号或分组后,定位在移动后的Label上 +- 切换图片时默认选中第一个Label + # 2.3.3 Fix diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 22d62aa..6c6f576 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -492,7 +492,7 @@ class Controller(private val state: State) { state.currentPicNameProperty().addListener(onChange { // If switch picture in CTreeView, the fours on TreeCell will not clear automatically // So we should manually clear it to make sure we start from the first label - cTreeView.selectRoot(clear = true, scrollTo = false) + cTreeView.selectFirst(clear = true, scrollTo = false) // Clear here, because the already happened selection may change it state.currentLabelIndex = NOT_FOUND }) @@ -610,13 +610,13 @@ class Controller(private val state: State) { // Mark immediately when this event will be consumed it.consume() // stop further propagation - val number = it.code.char.toInt() + val number = it.text.toInt() if (numberBuilder.isEmpty()) { // Not parsing if (number == 0) { // Start parse numberBuilder.append(0) - } else if (number in 1..state.transFile.groupCount) { + } else if (state.transFileProperty().isNotNull.isValid && number in 1..state.transFile.groupCount) { // Try select val index = number - 1 if (state.viewMode == ViewMode.GroupMode) { @@ -631,7 +631,7 @@ class Controller(private val state: State) { // Parsing numberBuilder.append(number) val index = numberBuilder.toString().toInt() - 1 - if (index in 0 until state.transFile.groupCount) { + if ( state.transFileProperty().isNotNull.isValid &&index in 0 until state.transFile.groupCount) { // Try select if (state.viewMode == ViewMode.GroupMode) { cTreeView.selectGroup(state.transFile.groupList[index].name, clear = true, scrollTo = false) @@ -647,23 +647,6 @@ class Controller(private val state: State) { } Logger.info("Transformed num-key pressed", "Controller") - // Transform Ctrl + Left/Right KeyEvent to CPicBox button click - val arrowKeyChangePicHandler = EventHandler handler@{ - if (!(it.isControlDown || it.isMetaDown)) return@handler - - when (it.code) { - KeyCode.LEFT -> cPicBox.back() - KeyCode.RIGHT -> cPicBox.next() - else -> return@handler - } - cLabelPane.fireEvent(keyEvent(it, code = KeyCode.DOWN, character = "", text = "")) - it.consume() // Consume used event - } - cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) - cTransArea.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) - cTreeView.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) - Logger.info("Transformed Ctrl + Left/Right", "Controller") - /** * Find next LabelItem as int index. * @return NOT_FOUND when have no next @@ -682,6 +665,41 @@ class Controller(private val state: State) { } } + fun moveCurrLabelTo(direction: Int) { + + var itemIndex = getNextLabelItemIndex(cTreeView.selectionModel.selectedIndex, direction) + if (itemIndex == NOT_FOUND) { + // if selected first and try getting previous, return last; + // if selected last and try getting next, return first; + itemIndex = getNextLabelItemIndex(if (direction == 1) 0 else cTreeView.expandedItemCount, direction) + } + if(itemIndex == NOT_FOUND) { + return + } + val item = cTreeView.getTreeItem(itemIndex) as CTreeLabelItem + + cLabelPane.moveToLabel(item.transLabel.index) + cTreeView.selectLabel(item.transLabel.index, clear = true, scrollTo = true) + } + + // Transform Ctrl + Left/Right KeyEvent to CPicBox button click + val arrowKeyChangePicHandler = EventHandler handler@{ + if (!(it.isControlDown || it.isMetaDown)) return@handler + + when (it.code) { + KeyCode.LEFT -> cPicBox.back() + KeyCode.RIGHT -> cPicBox.next() + else -> return@handler + } + moveCurrLabelTo(direction = 1) + it.consume() // Consume used event + } + cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) + cTransArea.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) + cTreeView.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) + Logger.info("Transformed Ctrl + Left/Right", "Controller") + + // Transform Ctrl + Up/Down KeyEvent to CTreeView select (and have effect: move to label) val arrowKeyChangeLabelHandler = EventHandler handler@{ if (!((it.isControlDown || it.isMetaDown) && it.code.isArrowKey)) return@handler @@ -696,16 +714,7 @@ class Controller(private val state: State) { // Mark immediately when this event will be consumed it.consume() // stop further propagation - var itemIndex = getNextLabelItemIndex(cTreeView.selectionModel.selectedIndex, itemShift) - if (itemIndex == NOT_FOUND) { - // if selected first and try getting previous, return last; - // if selected last and try getting next, return first; - itemIndex = getNextLabelItemIndex(if (itemShift == 1) 0 else cTreeView.expandedItemCount, itemShift) - } - val item = cTreeView.getTreeItem(itemIndex) as CTreeLabelItem - - cLabelPane.moveToLabel(item.transLabel.index) - cTreeView.selectLabel(item.transLabel.index, clear = true, scrollTo = true) + moveCurrLabelTo(itemShift) } cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangeLabelHandler) cTransArea.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangeLabelHandler) @@ -721,14 +730,14 @@ class Controller(private val state: State) { // transform if (it.isShiftDown) { // Met the bounds, change picture - if (itemIndex == NOT_FOUND) cLabelPane.fireEvent(keyEvent(it, code = KeyCode.LEFT, character = "", text = "")) + if (itemIndex == NOT_FOUND) cPicBox.back() // Go to previous label - cLabelPane.fireEvent(keyEvent(it, code = KeyCode.UP, character = "", text = "")) + moveCurrLabelTo(direction = -1) } else { // Met the bounds, change picture - if (itemIndex == NOT_FOUND) cLabelPane.fireEvent(keyEvent(it, code = KeyCode.RIGHT, character = "", text = "")) + if (itemIndex == NOT_FOUND) cPicBox.next() // Go to previous label - cLabelPane.fireEvent(keyEvent(it, code = KeyCode.DOWN, character = "", text = "")) + moveCurrLabelTo(direction = 1) } } diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index a1dd3e7..1e4126f 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -178,6 +178,7 @@ class CTreeMenu( { labelActions.forEach(Action::commit); state.controller.requestUpdateTree() }, { labelActions.forEach(Action::revert); state.controller.requestUpdateTree() } ) + view.selectLabel(items[0].transLabel.index, clear = true, scrollTo = true) state.doAction(moveAction) } private val lMoveToItem = MenuItem(I18N["context.move_to"]) @@ -198,16 +199,8 @@ class CTreeMenu( private val lMoveToLabelHandler = EventHandler { event -> @Suppress("UNCHECKED_CAST") val items = event.source as List val item = items.get(0) - val labels = state.transFile.getTransList(state.currentPicName).map(TransLabel::index); -// val groups = state.transFile.groupList.map(TransGroup::name) -// -// val dialog = ChoiceDialog(groups[0], groups).apply { -// initOwner(state.stage) -// title = I18N["context.move_to.dialog.title"] -// contentText = -// if (items.size == 1) I18N["context.move_to.dialog.header"] -// else I18N["context.move_to.dialog.header.pl"] -// } + val labels = state.transFile.getTransList(state.currentPicName).map(TransLabel::index) + val dialog = ChoiceDialog(labels[0], labels).apply { initOwner(state.stage) title = I18N["context.move_to_label.dialog.title"] @@ -228,6 +221,7 @@ class CTreeMenu( { labelAction.revert(); state.controller.requestUpdateTree() } ) state.doAction(moveAction) + view.selectLabel(choice.get(), clear = true, scrollTo = true) } private val lMoveToLabelItem = MenuItem(I18N["context.move_to_label"]) diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt index 6776821..59fa14b 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt @@ -181,6 +181,14 @@ class CTreeView: TreeView() { selectionModel.select(root) if (scrollTo) scrollTo(getRow(root)) } + fun selectFirst(clear: Boolean, scrollTo: Boolean) : Int { + if(labelItems.isEmpty()) { + selectRoot(clear, scrollTo) + return NOT_FOUND + } + selectLabel(labelItems[0].transLabel.index, clear, scrollTo) + return labelItems[0].transLabel.index + } fun selectGroup(groupName: String, clear: Boolean, scrollTo: Boolean) { // In IndexMode this is not available if (viewMode == ViewMode.IndexMode) return From f6788d0c528d7cf00a144714f8c535c48ac8bd77 Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 5 Mar 2023 23:02:40 +0800 Subject: [PATCH 14/28] fix some bug --- src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 6c6f576..af65636 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -616,7 +616,7 @@ class Controller(private val state: State) { if (number == 0) { // Start parse numberBuilder.append(0) - } else if (state.transFileProperty().isNotNull.isValid && number in 1..state.transFile.groupCount) { + } else if (state.transFileProperty().isNotNull.value && number in 1..state.transFile.groupCount) { // Try select val index = number - 1 if (state.viewMode == ViewMode.GroupMode) { @@ -631,7 +631,7 @@ class Controller(private val state: State) { // Parsing numberBuilder.append(number) val index = numberBuilder.toString().toInt() - 1 - if ( state.transFileProperty().isNotNull.isValid &&index in 0 until state.transFile.groupCount) { + if ( state.transFileProperty().isNotNull.value &&index in 0 until state.transFile.groupCount) { // Try select if (state.viewMode == ViewMode.GroupMode) { cTreeView.selectGroup(state.transFile.groupList[index].name, clear = true, scrollTo = false) From 35dabf8c04d579c503f4ff884804dca70ecf1f10 Mon Sep 17 00:00:00 2001 From: yeding Date: Fri, 17 Mar 2023 22:05:22 +0800 Subject: [PATCH 15/28] fix some bug --- .../kotlin/ink/meodinger/lpfx/Controller.kt | 25 ++++++++++++------- .../ink/meodinger/lpfx/action/LabelAction.kt | 17 +++++++------ .../ink/meodinger/lpfx/component/CTreeMenu.kt | 4 ++- .../ink/meodinger/lpfx/component/CTreeView.kt | 10 +++++++- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index af65636..7e41915 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -666,7 +666,6 @@ class Controller(private val state: State) { } fun moveCurrLabelTo(direction: Int) { - var itemIndex = getNextLabelItemIndex(cTreeView.selectionModel.selectedIndex, direction) if (itemIndex == NOT_FOUND) { // if selected first and try getting previous, return last; @@ -687,11 +686,11 @@ class Controller(private val state: State) { if (!(it.isControlDown || it.isMetaDown)) return@handler when (it.code) { - KeyCode.LEFT -> cPicBox.back() + KeyCode.LEFT -> cPicBox.back() KeyCode.RIGHT -> cPicBox.next() else -> return@handler } - moveCurrLabelTo(direction = 1) + cTreeView.selectFirst() it.consume() // Consume used event } cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, arrowKeyChangePicHandler) @@ -730,14 +729,22 @@ class Controller(private val state: State) { // transform if (it.isShiftDown) { // Met the bounds, change picture - if (itemIndex == NOT_FOUND) cPicBox.back() - // Go to previous label - moveCurrLabelTo(direction = -1) + if (itemIndex == NOT_FOUND) { + cPicBox.back() + cTreeView.selectLast() + } else { + // Go to previous label + moveCurrLabelTo(direction = -1) + } } else { // Met the bounds, change picture - if (itemIndex == NOT_FOUND) cPicBox.next() - // Go to previous label - moveCurrLabelTo(direction = 1) + if (itemIndex == NOT_FOUND) { + cPicBox.next() + cTreeView.selectFirst() + } else { + // Go to previous label + moveCurrLabelTo(direction = 1) + } } } diff --git a/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt b/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt index a5b0bd7..ebe43c1 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt @@ -53,12 +53,15 @@ class LabelAction( if (targetTransLabel.index == index) return val list = state.transFile.transMapObservable[targetPicName] ?: throw IllegalArgumentException(String.format(I18N["exception.action.picture_not_found.s"], targetPicName)) - if(index > targetTransLabel.index) { - for (label in list) if (label.index > targetTransLabel.index && label.index <= index) label.index-- - } else { - for (label in list) if (label.index >= index && label.index < targetTransLabel.index) label.index++ - } - targetTransLabel.index = index + val transLabel = TransLabel( + index, + targetTransLabel.groupId, + targetTransLabel.x, + targetTransLabel.y, + targetTransLabel.text + ) + removeTransLabel(targetPicName,targetTransLabel) + addTransLabel(targetPicName,transLabel) } if (newGroupId != NOT_FOUND) { builder.append("@groupId: ${targetTransLabel.groupId.pad(2)} -> ${groupId.pad(2)}; ") @@ -90,7 +93,7 @@ class LabelAction( throw IllegalArgumentException(String.format(I18N["exception.action.label_group_invalid.i"], transLabel.groupId)) for (label in list) if (label.index >= transLabel.index) label.index++ - list.add(transLabel) + list.add(transLabel.index -1 ,transLabel) @Suppress("DEPRECATION") state.transFile.installLabel(transLabel) Logger.info("Added $picName @ $transLabel", "Action") diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index 1e4126f..1a89c36 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -9,6 +9,7 @@ import ink.meodinger.lpfx.type.TransGroup import ink.meodinger.lpfx.util.color.toHexRGB import ink.meodinger.lpfx.util.component.withContent import ink.meodinger.lpfx.component.dialog.showError +import ink.meodinger.lpfx.options.Logger import ink.meodinger.lpfx.type.TransLabel import ink.meodinger.lpfx.util.doNothing import ink.meodinger.lpfx.util.property.transform @@ -178,8 +179,9 @@ class CTreeMenu( { labelActions.forEach(Action::commit); state.controller.requestUpdateTree() }, { labelActions.forEach(Action::revert); state.controller.requestUpdateTree() } ) - view.selectLabel(items[0].transLabel.index, clear = true, scrollTo = true) + val index = items[0].transLabel.index state.doAction(moveAction) + view.selectLabel(index, clear = true, scrollTo = true) } private val lMoveToItem = MenuItem(I18N["context.move_to"]) private val lDeleteHandler = EventHandler { event -> diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt index 59fa14b..1587fca 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt @@ -181,7 +181,7 @@ class CTreeView: TreeView() { selectionModel.select(root) if (scrollTo) scrollTo(getRow(root)) } - fun selectFirst(clear: Boolean, scrollTo: Boolean) : Int { + fun selectFirst(clear: Boolean = true, scrollTo: Boolean = true) : Int { if(labelItems.isEmpty()) { selectRoot(clear, scrollTo) return NOT_FOUND @@ -189,6 +189,14 @@ class CTreeView: TreeView() { selectLabel(labelItems[0].transLabel.index, clear, scrollTo) return labelItems[0].transLabel.index } + fun selectLast(clear: Boolean = true, scrollTo: Boolean = true) : Int { + if(labelItems.isEmpty()) { + selectRoot(clear, scrollTo) + return NOT_FOUND + } + selectLabel(labelItems.last().transLabel.index, clear, scrollTo) + return labelItems.last().transLabel.index + } fun selectGroup(groupName: String, clear: Boolean, scrollTo: Boolean) { // In IndexMode this is not available if (viewMode == ViewMode.IndexMode) return From e00297ffdcaf5e79628c33195499d4cda627438c Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 19 Mar 2023 15:11:16 +0800 Subject: [PATCH 16/28] add a hotkey of changing the picture in cLabelPane --- CHANGELOG | 3 ++- src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index dcdef8a..356f922 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,7 +12,7 @@ TODO: - 备份文件上限(Next) - 保存specify(Next) -# 2.3.3.1 +# 2.3.3.2 Fix @@ -21,6 +21,7 @@ Fix Add - 选中右键树状图中的Label支持移动序号 +- 图片区添加QW切换图片的快捷键 Change diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 7e41915..7cb01d9 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -751,6 +751,22 @@ class Controller(private val state: State) { cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, enterKeyTransformerHandler) cTransArea.addEventHandler(KeyEvent.KEY_PRESSED, enterKeyTransformerHandler) Logger.info("Transformed Ctrl + Enter", "Controller") + + val changePicHandler = EventHandler handler@{ + if (it.isControlDown || it.isMetaDown || it.isShiftDown || it.isAltDown || it.code.isDigitKey) return@handler + // Mark immediately when this event will be consumed + it.consume() // stop further propagation + + when (it.code) { + KeyCode.Q -> cPicBox.back() + KeyCode.W -> cPicBox.next() + else -> return@handler + } + cTreeView.selectFirst() + it.consume() // Consume used event + } + cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, changePicHandler) + Logger.info("Transformed A/D", "Controller") } // Controller Methods From 3895dfe742753d36f7eb41d33f3c3f1a338035ea Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 9 Apr 2023 14:59:17 +0800 Subject: [PATCH 17/28] support the copy and paste of label's text by menu or keywords;fix some bug --- CHANGELOG | 10 ++++ .../kotlin/ink/meodinger/lpfx/Controller.kt | 42 ++++++++++----- .../ink/meodinger/lpfx/action/LabelAction.kt | 2 - .../ink/meodinger/lpfx/component/CTreeMenu.kt | 29 +++++++++-- .../ink/meodinger/lpfx/component/CTreeView.kt | 51 ++++++++++++++++++- .../ink/meodinger/lpfx/LabelPlusFX.properties | 2 +- .../ink/meodinger/lpfx/Lang_en.properties | 2 + .../ink/meodinger/lpfx/Lang_zh_CN.properties | 5 +- .../ink/meodinger/lpfx/Lang_zh_TW.properties | 3 ++ 9 files changed, 125 insertions(+), 21 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 356f922..82ba618 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,16 @@ TODO: Fix +- 修复切换图片时默认选中第一个Label时文本框未切换的问题 + +Add + +- 树状图菜单添加复制文本和粘贴文本,并支持cv快捷键操作 + +# 2.3.3.2 + +Fix + - 尝试修复图片区数字快捷键报错 Add diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 7cb01d9..580d5b6 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -491,10 +491,12 @@ class Controller(private val state: State) { // This could clear the label-index related bindings like TransArea text state.currentPicNameProperty().addListener(onChange { // If switch picture in CTreeView, the fours on TreeCell will not clear automatically + //clear selection + state.currentLabelIndex = NOT_FOUND // So we should manually clear it to make sure we start from the first label - cTreeView.selectFirst(clear = true, scrollTo = false) + cTreeView.selectFirst(clear = true, scrollTo = false) // Clear here, because the already happened selection may change it - state.currentLabelIndex = NOT_FOUND +// state.currentLabelIndex = NOT_FOUND }) Logger.info("Listened for current-pic-name change for clear label-index selection", "Controller") @@ -577,7 +579,6 @@ class Controller(private val state: State) { */ private fun transform() { Logger.info("Applying Transformations...", "Controller") - // Transform tab press in CTreeView to ViewModeBtn click cTreeView.addEventFilter(KeyEvent.KEY_PRESSED) { if (it.code == KeyCode.TAB) { @@ -600,6 +601,22 @@ class Controller(private val state: State) { } Logger.info("Transformed Tab on CLabelPane", "Controller") + val changePicHandler = EventHandler handler@{ + if (it.isControlDown || it.isMetaDown || it.isShiftDown || it.isAltDown || it.code.isDigitKey) return@handler + // Mark immediately when this event will be consumed + it.consume() // stop further propagation + + when (it.code) { + KeyCode.Q -> cPicBox.back() + KeyCode.W -> cPicBox.next() + else -> return@handler + } + cTreeView.selectFirst() + it.consume() // Consume used event + } + cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, changePicHandler) + Logger.info("Transformed A/D", "Controller") + // Transform number key press to CTreeView select val numberBuilder = StringBuilder() view.addEventHandler(KeyEvent.KEY_PRESSED) handler@{ @@ -752,21 +769,22 @@ class Controller(private val state: State) { cTransArea.addEventHandler(KeyEvent.KEY_PRESSED, enterKeyTransformerHandler) Logger.info("Transformed Ctrl + Enter", "Controller") - val changePicHandler = EventHandler handler@{ - if (it.isControlDown || it.isMetaDown || it.isShiftDown || it.isAltDown || it.code.isDigitKey) return@handler - // Mark immediately when this event will be consumed - it.consume() // stop further propagation + + val copyLabelHandler = EventHandler handler@{ + if (!(it.isControlDown || it.isMetaDown)) return@handler when (it.code) { - KeyCode.Q -> cPicBox.back() - KeyCode.W -> cPicBox.next() + KeyCode.C -> cTreeView.copyLabelText(cTreeView.selectionModel.selectedIndex) + KeyCode.V -> cTreeView.pasteLabelText(cTreeView.selectionModel.selectedIndex,state) else -> return@handler } - cTreeView.selectFirst() it.consume() // Consume used event } - cLabelPane.addEventHandler(KeyEvent.KEY_PRESSED, changePicHandler) - Logger.info("Transformed A/D", "Controller") + cTreeView.addEventHandler(KeyEvent.KEY_PRESSED, copyLabelHandler) + Logger.info("Transformed Ctrl + C/V", "Controller") +// + + } // Controller Methods diff --git a/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt b/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt index ebe43c1..3b36243 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/action/LabelAction.kt @@ -51,8 +51,6 @@ class LabelAction( if (newLabelIndex != NOT_FOUND) { builder.append("@index: ${targetTransLabel.index.pad(2)} -> ${index.pad(2)}; ") if (targetTransLabel.index == index) return - val list = state.transFile.transMapObservable[targetPicName] - ?: throw IllegalArgumentException(String.format(I18N["exception.action.picture_not_found.s"], targetPicName)) val transLabel = TransLabel( index, targetTransLabel.groupId, diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index 1a89c36..863a1f4 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -179,9 +179,7 @@ class CTreeMenu( { labelActions.forEach(Action::commit); state.controller.requestUpdateTree() }, { labelActions.forEach(Action::revert); state.controller.requestUpdateTree() } ) - val index = items[0].transLabel.index state.doAction(moveAction) - view.selectLabel(index, clear = true, scrollTo = true) } private val lMoveToItem = MenuItem(I18N["context.move_to"]) private val lDeleteHandler = EventHandler { event -> @@ -200,6 +198,7 @@ class CTreeMenu( private val lMoveToLabelHandler = EventHandler { event -> @Suppress("UNCHECKED_CAST") val items = event.source as List + // choose the first transLabel val item = items.get(0) val labels = state.transFile.getTransList(state.currentPicName).map(TransLabel::index) @@ -223,11 +222,30 @@ class CTreeMenu( { labelAction.revert(); state.controller.requestUpdateTree() } ) state.doAction(moveAction) - view.selectLabel(choice.get(), clear = true, scrollTo = true) } private val lMoveToLabelItem = MenuItem(I18N["context.move_to_label"]) + private val lCopyLabelTextHandler = EventHandler { event -> + @Suppress("UNCHECKED_CAST") val items = event.source as List + // choose the first transLabel + val item = items.get(0) + view.copyLabelText(item.transLabel.index) + } + + private val lCopyLabelTextItem = MenuItem(I18N["context.copy_label_text"]) + + private val lPasteLabelTextHandler = EventHandler { event -> + @Suppress("UNCHECKED_CAST") val items = event.source as List + // choose the first transLabel + val item = items.get(0) + view.pasteLabelText(item.transLabel.index,state) + } + + private val lPasteLabelTextItem = MenuItem(I18N["context.paste_label_text"]) + + + // endregion init { @@ -280,11 +298,16 @@ class CTreeMenu( // label(s) lMoveToLabelItem.setOnAction { lMoveToLabelHandler.handle(ActionEvent(selectedItems, lMoveToLabelItem)) } lMoveToItem.setOnAction { lMoveToHandler.handle(ActionEvent(selectedItems, lMoveToItem)) } + lCopyLabelTextItem.setOnAction { lCopyLabelTextHandler.handle(ActionEvent(selectedItems, lCopyLabelTextItem)) } + lPasteLabelTextItem.setOnAction { lPasteLabelTextHandler.handle(ActionEvent(selectedItems, lPasteLabelTextItem)) } lDeleteItem.setOnAction { lDeleteHandler.handle(ActionEvent(selectedItems, lDeleteItem)) } items.add(lMoveToLabelItem) items.add(lMoveToItem) items.add(SeparatorMenuItem()) + items.add(lCopyLabelTextItem) + items.add(lPasteLabelTextItem) + items.add(SeparatorMenuItem()) items.add(lDeleteItem) } else { // other diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt index 1587fca..5be4449 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt @@ -1,6 +1,10 @@ package ink.meodinger.lpfx.component import ink.meodinger.lpfx.* +import ink.meodinger.lpfx.action.ActionType +import ink.meodinger.lpfx.action.FunctionAction +import ink.meodinger.lpfx.action.LabelAction +import ink.meodinger.lpfx.options.Logger import ink.meodinger.lpfx.type.TransGroup import ink.meodinger.lpfx.type.TransLabel import ink.meodinger.lpfx.util.component.expandAll @@ -13,6 +17,11 @@ import javafx.collections.FXCollections import javafx.collections.ListChangeListener import javafx.collections.ObservableList import javafx.scene.control.* +import javafx.scene.input.Clipboard +import javafx.scene.input.ClipboardContent + + + /** @@ -68,6 +77,15 @@ class CTreeView: TreeView() { private val groupItems: MutableList = ArrayList() private val labelItems: MutableList = ArrayList() +// private val copyTextProperty: StringProperty = SimpleStringProperty(emptyString()) +// +// /** +// * Selected copyText +// */ +// var copyText: String by copyTextProperty +// private set + + init { // Init @@ -128,6 +146,7 @@ class CTreeView: TreeView() { for ((groupId, transGroup) in groups.withIndex()) createGroupItem(transGroup, groupId) for (transLabel in labels) createLabelItem(transLabel) + selectLabel(selectedLabel, clear = true, scrollTo = true) } private fun createGroupItem(transGroup: TransGroup, groupId: Int) { val groupItem = CTreeGroupItem(transGroup) @@ -222,6 +241,34 @@ class CTreeView: TreeView() { if (scrollTo) scrollTo(getRow(items.first())) } + fun copyLabelText(labelIndex: Int) { + val item = labelItems.firstOrNull { it.transLabel.index == labelIndex } ?:return + val clipboard = Clipboard.getSystemClipboard() + val clipboardContent = ClipboardContent() + clipboardContent.putString(item.transLabel.text) + Logger.info("Copy text from the label which's num is $labelIndex", "CTreeView") + clipboard.setContent(clipboardContent) +// copyText = item.transLabel.text + } + + fun pasteLabelText(labelIndex: Int, state: State) { + val item = labelItems.firstOrNull { it.transLabel.index == labelIndex } ?:return + val clipboard = Clipboard.getSystemClipboard() + if (!clipboard.hasString()) return + Logger.info("Paste text into the label which's num is $labelIndex", "CTreeView") + val labelAction= LabelAction( + ActionType.CHANGE, state, + state.currentPicName, + state.transFile.getTransLabel(state.currentPicName, item.transLabel.index), + newText = clipboard.string + ) + val pasteAction = FunctionAction( + { labelAction.commit();}, + { labelAction.revert();} + ) + state.doAction(pasteAction) + } + /** * This will also clear the selected-index */ @@ -235,6 +282,8 @@ class CTreeView: TreeView() { * Request the TreeView to re-render. This function is useful * when some labels' group change in IndexMode. */ - fun requestUpdate() { update() } + fun requestUpdate() { + update() + } } diff --git a/src/main/resources/ink/meodinger/lpfx/LabelPlusFX.properties b/src/main/resources/ink/meodinger/lpfx/LabelPlusFX.properties index acbf2f0..84923a7 100644 --- a/src/main/resources/ink/meodinger/lpfx/LabelPlusFX.properties +++ b/src/main/resources/ink/meodinger/lpfx/LabelPlusFX.properties @@ -1,6 +1,6 @@ # application info application.name = LabelPlus FX -application.vendor = Meodinger (meodinger@qq.com) +application.vendor = Meodinger (meodinger@qq.com)、Yeding(kanaumachi@gmail.com) application.link = LabelPlusFX on GitHub application.url = https://github.com/Meodinger/LabelPlusFX application.help = https://www.kdocs.cn/l/seRSJCKVOn0Y \ No newline at end of file diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties index 511c039..2d542f0 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties @@ -84,6 +84,8 @@ context.move_to.dialog.header.pl = Please choose the group you want to move thes context.move_to_label = Move To Other Index context.move_to_label.dialog.title = Please choose the Index you want to move the label to context.move_to_label.dialog.header =Please choose the Index you want to move the label to +context.copy_label_text = Copy Text +context.paste_label_text = Paste Text context.delete_label = Delete # mode diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties index 7536a08..bec1bbd 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties @@ -81,11 +81,12 @@ context.move_to = 移动分组 context.move_to.dialog.title = 移动到其他分组 context.move_to.dialog.header = 请选择目标分组 context.move_to.dialog.header.pl = 请选择目标分组 -context.delete_label = 删除 context.move_to_label = 移动序号 context.move_to_label.dialog.title = 移动到其它序号 context.move_to_label.dialog.header = 请选择目标序号 - +context.copy_label_text = 复制文本 +context.paste_label_text = 粘贴文本 +context.delete_label = 删除 diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties index 3eb8f01..434f7e0 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties @@ -84,8 +84,11 @@ context.move_to.dialog.header.pl = 請選擇目標分組 context.move_to_label = 移動序號 context.move_to_label.dialog.title = 移動到其他序號 context.move_to_label.dialog.header = 请选择目标序號 +context.copy_label_text = 複製文本 +context.paste_label_text = 粘貼文本 context.delete_label = 删除 + # mode mode.work.input = 輸入模式 mode.work.label = 標號模式 From 68f055f1524630266d2d9d7c73ac282eaf81a076 Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 9 Apr 2023 15:00:22 +0800 Subject: [PATCH 18/28] fix CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 82ba618..1dfe599 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,7 +12,7 @@ TODO: - 备份文件上限(Next) - 保存specify(Next) -# 2.3.3.2 +# 2.3.3.3 Fix From 1d3891bdfb592d73dc2dd3c17ea91ad0651787d9 Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 9 Apr 2023 16:54:16 +0800 Subject: [PATCH 19/28] fix some bugs --- .../kotlin/ink/meodinger/lpfx/Controller.kt | 2 +- .../ink/meodinger/lpfx/component/CTreeMenu.kt | 21 ++++++------- .../ink/meodinger/lpfx/component/CTreeView.kt | 31 ++++++++++--------- .../ink/meodinger/lpfx/Lang_en.properties | 6 ++-- .../ink/meodinger/lpfx/Lang_zh_CN.properties | 6 ++-- .../ink/meodinger/lpfx/Lang_zh_TW.properties | 6 ++-- 6 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 580d5b6..64e824c 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -775,7 +775,7 @@ class Controller(private val state: State) { if (!(it.isControlDown || it.isMetaDown)) return@handler when (it.code) { KeyCode.C -> cTreeView.copyLabelText(cTreeView.selectionModel.selectedIndex) - KeyCode.V -> cTreeView.pasteLabelText(cTreeView.selectionModel.selectedIndex,state) + KeyCode.V -> cTreeView.pasteLabelText(cTreeView.selectionModel.selectedIndices,state) else -> return@handler } it.consume() // Consume used event diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index 863a1f4..69852ae 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -9,7 +9,6 @@ import ink.meodinger.lpfx.type.TransGroup import ink.meodinger.lpfx.util.color.toHexRGB import ink.meodinger.lpfx.util.component.withContent import ink.meodinger.lpfx.component.dialog.showError -import ink.meodinger.lpfx.options.Logger import ink.meodinger.lpfx.type.TransLabel import ink.meodinger.lpfx.util.doNothing import ink.meodinger.lpfx.util.property.transform @@ -196,16 +195,16 @@ class CTreeMenu( } private val lDeleteItem = MenuItem(I18N["context.delete_label"]) - private val lMoveToLabelHandler = EventHandler { event -> + private val lMoveToIndexHandler = EventHandler { event -> @Suppress("UNCHECKED_CAST") val items = event.source as List // choose the first transLabel - val item = items.get(0) + val item = items[0] val labels = state.transFile.getTransList(state.currentPicName).map(TransLabel::index) val dialog = ChoiceDialog(labels[0], labels).apply { initOwner(state.stage) - title = I18N["context.move_to_label.dialog.title"] - contentText = I18N["context.move_to_label.dialog.header"] + title = I18N["context.move_to_Index.dialog.title"] + contentText = I18N["context.move_to_index.dialog.header"] } val choice = dialog.showAndWait() if (!choice.isPresent) return@EventHandler @@ -224,12 +223,12 @@ class CTreeMenu( state.doAction(moveAction) } - private val lMoveToLabelItem = MenuItem(I18N["context.move_to_label"]) + private val lMoveToIndexItem = MenuItem(I18N["context.move_to_index"]) private val lCopyLabelTextHandler = EventHandler { event -> @Suppress("UNCHECKED_CAST") val items = event.source as List // choose the first transLabel - val item = items.get(0) + val item = items[0] view.copyLabelText(item.transLabel.index) } @@ -238,8 +237,8 @@ class CTreeMenu( private val lPasteLabelTextHandler = EventHandler { event -> @Suppress("UNCHECKED_CAST") val items = event.source as List // choose the first transLabel - val item = items.get(0) - view.pasteLabelText(item.transLabel.index,state) + + view.pasteLabelText(items.map { it.transLabel.index },state) } private val lPasteLabelTextItem = MenuItem(I18N["context.paste_label_text"]) @@ -296,13 +295,13 @@ class CTreeMenu( items.add(gDeleteItem) } else if (rootCount == 0 && groupCount == 0 && labelCount > 0) { // label(s) - lMoveToLabelItem.setOnAction { lMoveToLabelHandler.handle(ActionEvent(selectedItems, lMoveToLabelItem)) } + lMoveToIndexItem.setOnAction { lMoveToIndexHandler.handle(ActionEvent(selectedItems, lMoveToIndexItem)) } lMoveToItem.setOnAction { lMoveToHandler.handle(ActionEvent(selectedItems, lMoveToItem)) } lCopyLabelTextItem.setOnAction { lCopyLabelTextHandler.handle(ActionEvent(selectedItems, lCopyLabelTextItem)) } lPasteLabelTextItem.setOnAction { lPasteLabelTextHandler.handle(ActionEvent(selectedItems, lPasteLabelTextItem)) } lDeleteItem.setOnAction { lDeleteHandler.handle(ActionEvent(selectedItems, lDeleteItem)) } - items.add(lMoveToLabelItem) + items.add(lMoveToIndexItem) items.add(lMoveToItem) items.add(SeparatorMenuItem()) items.add(lCopyLabelTextItem) diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt index 5be4449..8f13f87 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt @@ -1,6 +1,7 @@ package ink.meodinger.lpfx.component import ink.meodinger.lpfx.* +import ink.meodinger.lpfx.action.Action import ink.meodinger.lpfx.action.ActionType import ink.meodinger.lpfx.action.FunctionAction import ink.meodinger.lpfx.action.LabelAction @@ -227,8 +228,8 @@ class CTreeView: TreeView() { if (scrollTo) scrollTo(getRow(item)) } fun selectLabel(labelIndex: Int, clear: Boolean, scrollTo: Boolean) { + val item = labelItems.firstOrNull{ it.transLabel.index == labelIndex } ?:return if (clear) clearSelection() - val item = labelItems.first { it.transLabel.index == labelIndex } selectionModel.select(item) if (scrollTo) scrollTo(getRow(item)) @@ -246,25 +247,27 @@ class CTreeView: TreeView() { val clipboard = Clipboard.getSystemClipboard() val clipboardContent = ClipboardContent() clipboardContent.putString(item.transLabel.text) - Logger.info("Copy text from the label which's num is $labelIndex", "CTreeView") + Logger.info("Copy text from the label of $labelIndex", "CTreeView") clipboard.setContent(clipboardContent) // copyText = item.transLabel.text } - fun pasteLabelText(labelIndex: Int, state: State) { - val item = labelItems.firstOrNull { it.transLabel.index == labelIndex } ?:return + fun pasteLabelText(labelIndexs: List, state: State) { + val indexs = labelItems.map { it.transLabel.index }.filter { labelIndexs.any { i -> i == it } } val clipboard = Clipboard.getSystemClipboard() - if (!clipboard.hasString()) return - Logger.info("Paste text into the label which's num is $labelIndex", "CTreeView") - val labelAction= LabelAction( - ActionType.CHANGE, state, - state.currentPicName, - state.transFile.getTransLabel(state.currentPicName, item.transLabel.index), - newText = clipboard.string - ) + if (!clipboard.hasString()||indexs.isEmpty()) return + Logger.info("Paste text into the labels of ${indexs.joinToString(separator = ",")}", "CTreeView") + val labelActions = indexs.map { + LabelAction( + ActionType.CHANGE, state, + state.currentPicName, + state.transFile.getTransLabel(state.currentPicName, it), + newText = clipboard.string + ) + } val pasteAction = FunctionAction( - { labelAction.commit();}, - { labelAction.revert();} + { labelActions.forEach(Action::commit) }, + { labelActions.forEach(Action::revert) } ) state.doAction(pasteAction) } diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties index 2d542f0..c1d0f34 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties @@ -81,9 +81,9 @@ context.move_to = Move To context.move_to.dialog.title = Move To Other Group context.move_to.dialog.header = Please choose the group you want to move the label to context.move_to.dialog.header.pl = Please choose the group you want to move these labels to -context.move_to_label = Move To Other Index -context.move_to_label.dialog.title = Please choose the Index you want to move the label to -context.move_to_label.dialog.header =Please choose the Index you want to move the label to +context.move_to_index = Move To Other Index +context.move_to_index.dialog.title = Please choose the Index you want to move the label to +context.move_to_index.dialog.header =Please choose the Index you want to move the label to context.copy_label_text = Copy Text context.paste_label_text = Paste Text context.delete_label = Delete diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties index bec1bbd..c1bf064 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties @@ -81,9 +81,9 @@ context.move_to = 移动分组 context.move_to.dialog.title = 移动到其他分组 context.move_to.dialog.header = 请选择目标分组 context.move_to.dialog.header.pl = 请选择目标分组 -context.move_to_label = 移动序号 -context.move_to_label.dialog.title = 移动到其它序号 -context.move_to_label.dialog.header = 请选择目标序号 +context.move_to_index = 移动序号 +context.move_to_index.dialog.title = 移动到其它序号 +context.move_to_index.dialog.header = 请选择目标序号 context.copy_label_text = 复制文本 context.paste_label_text = 粘贴文本 context.delete_label = 删除 diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties index 434f7e0..48d2ce5 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties @@ -81,9 +81,9 @@ context.move_to = 移動到… context.move_to.dialog.title = 移動到其他分組 context.move_to.dialog.header = 請選擇目標分組 context.move_to.dialog.header.pl = 請選擇目標分組 -context.move_to_label = 移動序號 -context.move_to_label.dialog.title = 移動到其他序號 -context.move_to_label.dialog.header = 请选择目标序號 +context.move_to_index = 移動序號 +context.move_to_index.dialog.title = 移動到其他序號 +context.move_to_index.dialog.header = 请选择目标序號 context.copy_label_text = 複製文本 context.paste_label_text = 粘貼文本 context.delete_label = 删除 From 9dd33558b3a9083477ac05275439f7e61d5f414b Mon Sep 17 00:00:00 2001 From: yeding Date: Fri, 26 May 2023 14:14:39 +0800 Subject: [PATCH 20/28] fix some bugs --- .../kotlin/ink/meodinger/lpfx/Controller.kt | 18 +++++++++++++++--- .../ink/meodinger/lpfx/component/CTreeMenu.kt | 4 ++-- .../ink/meodinger/lpfx/component/CTreeView.kt | 12 +++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 64e824c..5dd9516 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -774,9 +774,21 @@ class Controller(private val state: State) { val copyLabelHandler = EventHandler handler@{ if (!(it.isControlDown || it.isMetaDown)) return@handler when (it.code) { - KeyCode.C -> cTreeView.copyLabelText(cTreeView.selectionModel.selectedIndex) - KeyCode.V -> cTreeView.pasteLabelText(cTreeView.selectionModel.selectedIndices,state) - else -> return@handler + KeyCode.C -> // cTreeView.pasteLabelsText(selectItems.map { it.transLabel.index },state) + { + cTreeView.copyLabelText(cTreeView.selectionModel.selectedIndex) + } + KeyCode.V -> { + @Suppress("UNCHECKED_CAST") val selectItems:Collection = + cTreeView.selectionModel.selectedIndices.map { cTreeView.getTreeItem(it)} + .filter { it is CTreeLabelItem } as List + cTreeView.pasteLabelsText(selectItems.map { it.transLabel.index },state) + } + else ->// cTreeView.pasteLabelsText(selectItems.map { it.transLabel.index },state) + // cTreeView.pasteLabelsText(selectItems.map { it.transLabel.index },state) + { + return@handler + } } it.consume() // Consume used event } diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index 69852ae..2c910a2 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -203,7 +203,7 @@ class CTreeMenu( val dialog = ChoiceDialog(labels[0], labels).apply { initOwner(state.stage) - title = I18N["context.move_to_Index.dialog.title"] + title = I18N["context.move_to_index.dialog.title"] contentText = I18N["context.move_to_index.dialog.header"] } val choice = dialog.showAndWait() @@ -238,7 +238,7 @@ class CTreeMenu( @Suppress("UNCHECKED_CAST") val items = event.source as List // choose the first transLabel - view.pasteLabelText(items.map { it.transLabel.index },state) + view.pasteLabelsText(items.map { it.transLabel.index },state) } private val lPasteLabelTextItem = MenuItem(I18N["context.paste_label_text"]) diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt index 8f13f87..c374c07 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt @@ -243,6 +243,8 @@ class CTreeView: TreeView() { } fun copyLabelText(labelIndex: Int) { +// val indexes = labelItems.filter { labelIndexes.any { i -> i == it.transLabel.index } } +// if (indexes.isEmpty()) return val item = labelItems.firstOrNull { it.transLabel.index == labelIndex } ?:return val clipboard = Clipboard.getSystemClipboard() val clipboardContent = ClipboardContent() @@ -252,12 +254,12 @@ class CTreeView: TreeView() { // copyText = item.transLabel.text } - fun pasteLabelText(labelIndexs: List, state: State) { - val indexs = labelItems.map { it.transLabel.index }.filter { labelIndexs.any { i -> i == it } } + fun pasteLabelsText(labelIndexes: Collection, state: State) { + val indexes = labelItems.map { it.transLabel.index }.filter { labelIndexes.any { i -> i == it } } val clipboard = Clipboard.getSystemClipboard() - if (!clipboard.hasString()||indexs.isEmpty()) return - Logger.info("Paste text into the labels of ${indexs.joinToString(separator = ",")}", "CTreeView") - val labelActions = indexs.map { + if (!clipboard.hasString()||indexes.isEmpty()) return + Logger.info("Paste text into the labels of ${indexes.joinToString(separator = ",")}", "CTreeView") + val labelActions = indexes.map { LabelAction( ActionType.CHANGE, state, state.currentPicName, From fab47bed32999864b2b3216ddeba91a1ce02f0ff Mon Sep 17 00:00:00 2001 From: yeding Date: Sat, 2 Sep 2023 22:55:50 +0900 Subject: [PATCH 21/28] fix some bugs --- src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 5dd9516..858df95 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -776,10 +776,11 @@ class Controller(private val state: State) { when (it.code) { KeyCode.C -> // cTreeView.pasteLabelsText(selectItems.map { it.transLabel.index },state) { - cTreeView.copyLabelText(cTreeView.selectionModel.selectedIndex) + @Suppress("UNCHECKED_CAST") val treeItem = cTreeView.getTreeItem(cTreeView.selectionModel.selectedIndex) as CTreeLabelItem + cTreeView.copyLabelText(treeItem.transLabel.index) } KeyCode.V -> { - @Suppress("UNCHECKED_CAST") val selectItems:Collection = + @Suppress("UNCHECKED_CAST") val selectItems:Collection = cTreeView.selectionModel.selectedIndices.map { cTreeView.getTreeItem(it)} .filter { it is CTreeLabelItem } as List cTreeView.pasteLabelsText(selectItems.map { it.transLabel.index },state) From 3a38e4dcb647e6568a6c07c44782da52d6de4f19 Mon Sep 17 00:00:00 2001 From: yeding Date: Sat, 30 Sep 2023 16:55:15 +0900 Subject: [PATCH 22/28] fix some bugs --- src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 1 + src/main/kotlin/ink/meodinger/lpfx/component/CLabelPane.kt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index 858df95..e056854 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -495,6 +495,7 @@ class Controller(private val state: State) { state.currentLabelIndex = NOT_FOUND // So we should manually clear it to make sure we start from the first label cTreeView.selectFirst(clear = true, scrollTo = false) + cLabelPane.moveToLabel(cTreeView.selectedLabel) // Clear here, because the already happened selection may change it // state.currentLabelIndex = NOT_FOUND }) diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CLabelPane.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CLabelPane.kt index 7539762..3a6a82f 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CLabelPane.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CLabelPane.kt @@ -845,7 +845,8 @@ class CLabelPane : ScrollPane() { * @param labelIndex Index of the label which will be displaye at the center */ fun moveToLabel(labelIndex: Int) { - val label = labelNodes.first { it.index == labelIndex } + val label = labelNodes.firstOrNull { it.index == labelIndex } ?:return + vvalue = 0.0 hvalue = 0.0 From cbb3916a32b6297dca4a5ffcd7d05b860ffbdaec Mon Sep 17 00:00:00 2001 From: yeding Date: Sun, 11 Aug 2024 13:59:14 +0900 Subject: [PATCH 23/28] 2.3.3.4 update --- CHANGELOG | 8 ++++++++ src/main/kotlin/ink/meodinger/lpfx/Controller.kt | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 1dfe599..268cadc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,14 @@ TODO: - 备份文件上限(Next) - 保存specify(Next) + # 2.3.3.4 + + Fix + + - 暂时通过限制加载时图片的大小修复了图片文件尺寸过大导致卡死的问题 + - 修复了复制文本和粘贴文本时产生的bug + + # 2.3.3.3 Fix diff --git a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt index e056854..8fee3d0 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Controller.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Controller.kt @@ -143,7 +143,13 @@ class Controller(private val state: State) { // Opened and selected val file = state.getPicFileNow() if (file.exists()) { - val imageByFX = Image(file.toURI().toURL().toString()) + var imageByFX = Image(file.toURI().toURL().toString()) + + //if the image is too large,limit the size of image + if(imageByFX.width > 5000 || imageByFX.height > 5000) { + Logger.info("limit the size of image because `$file` is too large ", "Controller") + imageByFX = Image(file.toURI().toURL().toString(),5000.0,5000.0,true,true) + } if (!imageByFX.isError) { imageByFX From d05f7865a89b24605afde6a5e7011e4c8d0aa7f1 Mon Sep 17 00:00:00 2001 From: Ye Ding <“kanaumachi@gmail.com”> Date: Sun, 6 Oct 2024 11:31:31 +0900 Subject: [PATCH 24/28] release 2.3.4 --- CHANGELOG => CHANGELOG.md | 32 ++---- script/jpackage/build.bat | 6 +- .../kotlin/ink/meodinger/lpfx/Constants.kt | 2 +- src/main/kotlin/ink/meodinger/lpfx/View.kt | 12 +- .../ink/meodinger/lpfx/component/CTextMenu.kt | 99 ++++++++++++++++ .../ink/meodinger/lpfx/component/CTreeMenu.kt | 2 - .../ink/meodinger/lpfx/component/CTreeView.kt | 4 +- .../component/properties/DialogSettings.kt | 108 ++++++++++++++++++ .../kotlin/ink/meodinger/lpfx/io/Translate.kt | 9 +- .../ink/meodinger/lpfx/Lang_en.properties | 18 +++ .../ink/meodinger/lpfx/Lang_zh_CN.properties | 18 ++- .../ink/meodinger/lpfx/Lang_zh_TW.properties | 17 +++ 12 files changed, 290 insertions(+), 37 deletions(-) rename CHANGELOG => CHANGELOG.md (94%) create mode 100644 src/main/kotlin/ink/meodinger/lpfx/component/CTextMenu.kt diff --git a/CHANGELOG b/CHANGELOG.md similarity index 94% rename from CHANGELOG rename to CHANGELOG.md index 268cadc..cd712b6 100644 --- a/CHANGELOG +++ b/CHANGELOG.md @@ -12,40 +12,26 @@ TODO: - 备份文件上限(Next) - 保存specify(Next) - # 2.3.3.4 - - Fix - - - 暂时通过限制加载时图片的大小修复了图片文件尺寸过大导致卡死的问题 - - 修复了复制文本和粘贴文本时产生的bug - - -# 2.3.3.3 - -Fix - -- 修复切换图片时默认选中第一个Label时文本框未切换的问题 +# 2.3.4 Add -- 树状图菜单添加复制文本和粘贴文本,并支持cv快捷键操作 - -# 2.3.3.2 + - 编辑框添加快捷输入短语 + - 树状图菜单添加复制文本和粘贴文本,并支持cv快捷键操作 + - 选中右键树状图中的Label支持移动序号 + - 图片区添加QW切换图片的快捷键 + - 添加百度翻译key设置用于配置繁简体转换 Fix -- 尝试修复图片区数字快捷键报错 - -Add - -- 选中右键树状图中的Label支持移动序号 -- 图片区添加QW切换图片的快捷键 +- 尝试通过限制加载时图片的大小以及给予更多内存空间的方式修复图片文件尺寸过大导致卡死的问题 +- 尝试修复图片区数字快捷键报错、 Change -- 移动Label序号或分组后,定位在移动后的Label上 - 切换图片时默认选中第一个Label + # 2.3.3 Fix diff --git a/script/jpackage/build.bat b/script/jpackage/build.bat index 45a30bc..ccb4e3b 100644 --- a/script/jpackage/build.bat +++ b/script/jpackage/build.bat @@ -6,7 +6,9 @@ rd /S /Q ".\LabelPlusFX" set MODULES="%DIR%\target\build" set ICON="%DIR%\images\icons\cat.ico" -jpackage --verbose --type app-image --app-version 2.3.3 --copyright "Meodinger Tech (C) 2022" --name LabelPlusFX --icon %ICON% --dest . --module-path %MODULES% --add-modules lpfx,jdk.crypto.cryptoki --module lpfx/ink.meodinger.lpfx.LauncherKt +jpackage --verbose --type app-image --app-version 2.3.4 --copyright "Meodinger Tech (C) 2022" --name LabelPlusFX --icon %ICON% --dest . --module-path %MODULES% --add-modules lpfx,jdk.crypto.cryptoki --module lpfx/ink.meodinger.lpfx.LauncherKt --java-options "-Dprism.maxvram=2G" echo: -echo All completed, remember to copy dlls! \ No newline at end of file +echo All completed, remember to copy dlls! + +pause \ No newline at end of file diff --git a/src/main/kotlin/ink/meodinger/lpfx/Constants.kt b/src/main/kotlin/ink/meodinger/lpfx/Constants.kt index c9897ed..e221996 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Constants.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Constants.kt @@ -16,7 +16,7 @@ import java.io.File /** * Current Version */ -val V: Version = Version(2, 3, 3) +val V: Version = Version(2, 3, 4) /** * Default Filename Placeholder. It's Esperanto! diff --git a/src/main/kotlin/ink/meodinger/lpfx/View.kt b/src/main/kotlin/ink/meodinger/lpfx/View.kt index fd5c4d4..f7264b2 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/View.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/View.kt @@ -124,9 +124,11 @@ class View(private val state: State) : BorderPane() { */ val cTransArea: CLigatureArea = CLigatureArea() + // Private Components private val statsBar: HBox = HBox() private val cTreeMenu: CTreeMenu = CTreeMenu(state, cTreeView) + private val cTextMenu: CTextMenu = CTextMenu(cTransArea) // endregion @@ -230,6 +232,9 @@ class View(private val state: State) : BorderPane() { item(I18N["m.bak_recovery"]) { does { bakRecovery() } } + item(I18N["m.settings"]) { + does { settings() } + } separator() item(I18N["m.exit"]) { does { exitApplication() } @@ -311,9 +316,6 @@ class View(private val state: State) : BorderPane() { } } menu(I18N["mm.about"]) { - item(I18N["m.settings"]) { - does { settings() } - } item(I18N["m.logs"]) { does { logs() } } @@ -771,6 +773,7 @@ class View(private val state: State) : BorderPane() { Settings.DefaultGroupColorHexList -> Settings.defaultGroupColorHexList .setAll(value as List) Settings.IsGroupCreateOnNewTrans -> Settings.isGroupCreateOnNewTransList .setAll(value as List) Settings.LigatureRules -> Settings.ligatureRules .setAll(value as List>) + Settings.QuickInputTexts -> Settings.quickInputTexts .setAll(value as List) Settings.ViewModes -> Settings.viewModes .setAll(value as List) Settings.NewPictureScale -> Settings.newPictureScalePicture = value as CLabelPane.NewPictureScale Settings.UseWheelToScale -> Settings.useWheelToScale = value as Boolean @@ -784,6 +787,9 @@ class View(private val state: State) : BorderPane() { Settings.UseMeoFileAsDefault -> Settings.useMeoFileAsDefault = value as Boolean Settings.UseExportNameTemplate -> Settings.useExportNameTemplate = value as Boolean Settings.ExportNameTemplate -> Settings.exportNameTemplate = value as String + Settings.UseCustomBaiduKey -> Settings.useCustomBaiduKey = value as Boolean + Settings.BaiduTransLateKey -> Settings.baiduTransLateKey = value as String + Settings.BaiduTransLateAppId -> Settings.baiduTransLateAppId = value as String else -> doNothing() } } diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTextMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTextMenu.kt new file mode 100644 index 0000000..de36a29 --- /dev/null +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTextMenu.kt @@ -0,0 +1,99 @@ +package ink.meodinger.lpfx.component + +import ink.meodinger.lpfx.I18N +import ink.meodinger.lpfx.get +import ink.meodinger.lpfx.options.Logger +import ink.meodinger.lpfx.options.Settings +import ink.meodinger.lpfx.util.property.onChange +import javafx.event.EventHandler +import javafx.scene.control.* + +class CTextMenu( + private val textField: TextInputControl +) : ContextMenu() { + + // add default menu items + private val undoMI = MenuItem(I18N["input.menu.undo"]).apply { + onAction = EventHandler { textField.undo() } + } + private val redoMI = MenuItem(I18N["input.menu.redo"]).apply { + onAction = EventHandler { textField.redo() } + } + private val cutMI = MenuItem(I18N["input.menu.cut"]).apply { + onAction = EventHandler { textField.cut() } + } + private val copyMI = MenuItem(I18N["input.menu.copy"]).apply { + onAction = EventHandler { textField.copy() } + } + private val pasteMI = MenuItem(I18N["input.menu.paste"]).apply { + onAction = EventHandler { textField.paste() } + } + private val deleteMI = MenuItem(I18N["input.menu.delete_selection"]).apply { + onAction = EventHandler { deleteSelectedText(textField) } + } + private val selectAllMI = MenuItem(I18N["input.menu.select_all"]).apply { + onAction = EventHandler { textField.selectAll() } + } + + // add custom menu items + private val quickInput = Menu(I18N["input.menu.quick_input"]) + + + init { + textField.undoableProperty() + .addListener { _, _, newValue -> + undoMI.isDisable = + !newValue!! + } + textField.redoableProperty() + .addListener { _, _, newValue -> + redoMI.isDisable = + !newValue!! + } + textField.selectionProperty() + .addListener { _, _, newValue -> + cutMI.isDisable = + newValue.length == 0 + copyMI.isDisable = newValue.length == 0 + deleteMI.isDisable = newValue.length == 0 + selectAllMI.isDisable = newValue.length == newValue.end + } + + //init QuickInputItems + initQuickInputItems(quickInput) + textField.contextMenu = ContextMenu( + undoMI, redoMI, cutMI, copyMI, pasteMI, deleteMI, SeparatorMenuItem(), selectAllMI, quickInput + ) + } + + private fun deleteSelectedText(t: TextInputControl) { + val range = t.selection + if (range.length == 0) { + return + } + val text = t.text + val newText = text.substring(0, range.start) + text.substring(range.end) + t.text = newText + t.positionCaret(range.start) + } + + private fun initQuickInputItems(menu: Menu) { + menu.items.clear() + menu.items.addAll(getQuickInputItems(textField)) + Settings.quickInputTextsProperty.addListener( onChange { + Logger.info("refresh the quick input items", "CTextMenu") + menu.items.clear() + menu.items.addAll(getQuickInputItems(textField)) + }) + } + + private fun getQuickInputItems(t: TextInputControl): List { + return Settings.quickInputTexts.map { + MenuItem(it).apply { + onAction = EventHandler { t.appendText(text) } + } + } + } + + +} diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt index 2c910a2..d4055fe 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeMenu.kt @@ -236,8 +236,6 @@ class CTreeMenu( private val lPasteLabelTextHandler = EventHandler { event -> @Suppress("UNCHECKED_CAST") val items = event.source as List - // choose the first transLabel - view.pasteLabelsText(items.map { it.transLabel.index },state) } diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt index c374c07..43942c7 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/CTreeView.kt @@ -243,15 +243,12 @@ class CTreeView: TreeView() { } fun copyLabelText(labelIndex: Int) { -// val indexes = labelItems.filter { labelIndexes.any { i -> i == it.transLabel.index } } -// if (indexes.isEmpty()) return val item = labelItems.firstOrNull { it.transLabel.index == labelIndex } ?:return val clipboard = Clipboard.getSystemClipboard() val clipboardContent = ClipboardContent() clipboardContent.putString(item.transLabel.text) Logger.info("Copy text from the label of $labelIndex", "CTreeView") clipboard.setContent(clipboardContent) -// copyText = item.transLabel.text } fun pasteLabelsText(labelIndexes: Collection, state: State) { @@ -274,6 +271,7 @@ class CTreeView: TreeView() { state.doAction(pasteAction) } + /** * This will also clear the selected-index */ diff --git a/src/main/kotlin/ink/meodinger/lpfx/component/properties/DialogSettings.kt b/src/main/kotlin/ink/meodinger/lpfx/component/properties/DialogSettings.kt index fb700ac..3502ad3 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/component/properties/DialogSettings.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/component/properties/DialogSettings.kt @@ -46,6 +46,7 @@ class DialogSettings : AbstractPropertiesDialog() { companion object { private const val gRowShift = 1 private const val rRowShift = 1 + private const val qRowShift = 1 private const val rIsFrom = "C_Is_From" private const val rRuleIndex = "C_Rule_Index" } @@ -71,6 +72,14 @@ class DialogSettings : AbstractPropertiesDialog() { private val rLabelFrom = Label(I18N["settings.ligature.from"]) private val rLabelTo = Label(I18N["settings.ligature.to"]) + private val qGridPane = GridPane().apply { + alignment = Pos.TOP_CENTER + padding = Insets(16.0) + vgap = 16.0 + hgap = 16.0 + } + private val qLabelHint = Label(I18N["settings.quick_input.hint"]) + private val mComboInput = CComboBox() private val mComboLabel = CComboBox() private val mComboScale = CComboBox() @@ -91,6 +100,9 @@ class DialogSettings : AbstractPropertiesDialog() { private val xCheckUseMeo = CheckBox(I18N["settings.other.meo_default"]) private val xCheckUseTmp = CheckBox(I18N["settings.other.template.enable"]) private val xFieldTemplate = TextField() + private val xCheckUseCustomBaiduKey = CheckBox(I18N["settings.other.Translate_keys.enable"]) + private val xFieldBaiduTranslateKey = TextField() + private val xFieldBaiduTranslateAppId = TextField() init { title = I18N["settings.title"] @@ -130,6 +142,22 @@ class DialogSettings : AbstractPropertiesDialog() { } } } + add(I18N["settings.quick_input.title"]) { + withContent(BorderPane()) { + val stackPane = StackPane(qGridPane) + val scrollPane = ScrollPane(stackPane) + stackPane.prefWidthProperty().bind(scrollPane.widthProperty() - 16.0) + + center(scrollPane) { style = "-fx-background-color:transparent;" } + bottom(HBox()) { + alignment = Pos.CENTER_RIGHT + padding = Insets(16.0, 8.0, 8.0, 16.0) + add(Label(I18N["settings.quick_input.sample"])) + add(HBox()) { hgrow = Priority.ALWAYS } + add(Button(I18N["settings.quick_input.add"])) { does { createQuickInputRow() } } + } + } + } add(I18N["settings.mode.title"]) { withContent(GridPane()) { alignment = Pos.TOP_CENTER @@ -348,6 +376,16 @@ class DialogSettings : AbstractPropertiesDialog() { showDelay = Duration(500.0) } } + add(xCheckUseCustomBaiduKey, 0, 7, 2, 1) + add(Label(I18N["settings.other.Translate_keys.key"]), 0, 8) + add(xFieldBaiduTranslateKey, 1, 8) { + disableProperty().bind(!xCheckUseCustomBaiduKey.selectedProperty()) + + } + add(Label(I18N["settings.other.Translate_keys.app_id"]), 0, 9) + add(xFieldBaiduTranslateAppId, 1, 9) { + disableProperty().bind(!xCheckUseCustomBaiduKey.selectedProperty()) + } } } } @@ -471,6 +509,50 @@ class DialogSettings : AbstractPropertiesDialog() { } } + // ----- Quick Input ----- // + private fun initQuickInputTab() { + qGridPane.children.clear() + + val quickInputTextsList = Settings.quickInputTexts + + if (quickInputTextsList.isEmpty()) { + qGridPane.add(qLabelHint, 0, 0) + } else { + for ( text in quickInputTextsList) createQuickInputRow(text) + } + } + private fun createQuickInputRow(text: String = "") { + val newRowIndex = if (qGridPane.rowCount == 0) 1 else qGridPane.rowCount + if (qGridPane.children.size == 1 || qGridPane.rowCount == 0) { // Only hint || nothing + qGridPane.children.clear() + } + val textField = TextField(text).apply { + textFormatter = genGeneralFormatter() + } + val button = Button(I18N["common.delete"]) does { removeQuickInputRow(GridPane.getRowIndex(this)) } + // 0 1 2 + // 1 textField ________ Delete + qGridPane.add(textField, 0, newRowIndex) + qGridPane.add(button, 1, newRowIndex) + } + private fun removeQuickInputRow(index: Int) { + val toRemoveSet = HashSet() + for (node in qGridPane.children) { + val row = GridPane.getRowIndex(node) ?: 0 + if (row == index) toRemoveSet.add(node) + if (row > index) { + GridPane.setRowIndex(node, row - 1) + } + } + qGridPane.children.removeAll(toRemoveSet) + + if (qGridPane.rowCount == qRowShift) { + qGridPane.children.removeAll() + qGridPane.add(qLabelHint, 0, 0) + } + } + + // ----- Initialize Properties ----- // override fun initProperties() { // Group @@ -479,6 +561,9 @@ class DialogSettings : AbstractPropertiesDialog() { // Ligature Rule initLigatureTab() + // quick Input + initQuickInputTab() + // Mode mComboInput.select(Settings.viewModes[0]) mComboLabel.select(Settings.viewModes[1]) @@ -505,6 +590,9 @@ class DialogSettings : AbstractPropertiesDialog() { xCheckUseMeo.isSelected = Settings.useMeoFileAsDefault xCheckUseTmp.isSelected = Settings.useExportNameTemplate xFieldTemplate.text = Settings.exportNameTemplate + xCheckUseCustomBaiduKey.isSelected = Settings.useCustomBaiduKey + xFieldBaiduTranslateKey.text = Settings.baiduTransLateKey + xFieldBaiduTranslateAppId.text = Settings.baiduTransLateAppId } // ----- Result convert ---- // @@ -557,6 +645,22 @@ class DialogSettings : AbstractPropertiesDialog() { return map } + private fun convertQuickInput(): Map { + val map = HashMap() + val size = qGridPane.rowCount - qRowShift + if (size < 0) return emptyMap() + + val textList = MutableList(size) { "" } + for (node in qGridPane.children) { + val groupId = GridPane.getRowIndex(node) - qRowShift + if (groupId < 0) continue + when (node) { + is TextField -> textList[groupId] = node.text + } + } + map[Settings.QuickInputTexts] = textList + return map + } private fun convertMode(): Map { val map = HashMap() @@ -585,6 +689,9 @@ class DialogSettings : AbstractPropertiesDialog() { map[Settings.UseMeoFileAsDefault] = xCheckUseMeo.isSelected map[Settings.UseExportNameTemplate] = xCheckUseTmp.isSelected map[Settings.ExportNameTemplate] = xFieldTemplate.text + map[Settings.UseCustomBaiduKey] = xCheckUseCustomBaiduKey.isSelected + map[Settings.BaiduTransLateKey] = xFieldBaiduTranslateKey.text + map[Settings.BaiduTransLateAppId] = xFieldBaiduTranslateAppId.text return map } @@ -593,6 +700,7 @@ class DialogSettings : AbstractPropertiesDialog() { return HashMap().apply { putAll(convertGroup()) putAll(convertLigatureRule()) + putAll(convertQuickInput()) putAll(convertMode()) putAll(convertLabel()) putAll(convertOther()) diff --git a/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt b/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt index 5649d5a..350734b 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt @@ -1,6 +1,8 @@ package ink.meodinger.lpfx.util.translator import com.fasterxml.jackson.databind.ObjectMapper +import ink.meodinger.lpfx.options.Logger +import ink.meodinger.lpfx.options.Settings import java.io.IOException import java.net.* import java.nio.charset.Charset @@ -31,9 +33,12 @@ private fun md5(text: String): String { } private fun query(q: String, from: String, to: String): String { val salt = floor(Math.random() * 10000) - val sign = md5("$ID$q$salt$KEY").lowercase() + val key = if (Settings.useCustomBaiduKey) Settings.baiduTransLateKey else KEY + val appId = if (Settings.useCustomBaiduKey) Settings.baiduTransLateAppId else ID + val sign = md5("$appId$q$salt$key").lowercase() + Logger.info(Settings.baiduTransLateAppId+ ","+Settings.baiduTransLateKey, "Controller") - return "$ROOT?q=${URLEncoder.encode(q, utf8Charset)}&from=$from&to=$to&appid=$ID&salt=$salt&sign=$sign" + return "$ROOT?q=${URLEncoder.encode(q, utf8Charset)}&from=$from&to=$to&appid=$appId&salt=$salt&sign=$sign" } /** diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties index c1d0f34..c92f8b0 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_en.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_en.properties @@ -88,6 +88,16 @@ context.copy_label_text = Copy Text context.paste_label_text = Paste Text context.delete_label = Delete +## input +input.menu.undo=Undo +input.menu.redo=Redo +input.menu.cut=Cut +input.menu.copy=Copy +input.menu.paste=Paste +input.menu.select_all=Select All +input.menu.quick_input=Quick Input + + # mode mode.work.label = Label Mode mode.work.input = Input Mode @@ -230,6 +240,11 @@ settings.ligature.from = From settings.ligature.to = To settings.ligature.add = Add Rule settings.ligature.sample = For example: From `star` to `⭐`, Input `\\star` will auto transform to `⭐` +## quick input +settings.quick_input.title = Quick Input +settings.quick_input.hint = No Phrase, you can create one +settings.quick_input.add = Add Phrase +settings.quick_input.sample = Right-click the text area,and you can use the quick input ## mode settings.mode.title = Mode settings.mode.scale.label = Scale on new picture @@ -250,6 +265,9 @@ settings.other.meo_default = Use MeoFile as default save format settings.other.template.enable = Use template when export translation settings.other.template.hint = Available variables: %FILE% Filename, %DIR% Dirname, %PROJECT% Project name\nCannot contain chars of * : ? < > | / " \\ settings.other.template.default = %FILE% Translator:XXX +settings.other.Translate_keys.enable = User your keys of baidu translate +settings.other.Translate_keys.key = Key +settings.other.Translate_keys.app_id = APP ID # logs logs.title = Logs diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties index c1bf064..a9627bb 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_CN.properties @@ -63,7 +63,6 @@ m.externalPic.dialog.header = 以下文件名有冲突!将不会被添加到 stats.not_backed = 未进行过备份 stats.last_backup.s = 上次备份于:%s stats.accumulator.s = 累计编辑时间:%s - # context menu context.error.same_group_name = 已经有相同名称分组 ## root @@ -88,6 +87,15 @@ context.copy_label_text = 复制文本 context.paste_label_text = 粘贴文本 context.delete_label = 删除 +## input +input.menu.undo=撤销 +input.menu.redo=重做 +input.menu.cut=剪切 +input.menu.copy=复制 +input.menu.paste=粘贴 +input.menu.delete_selection=删除 +input.menu.select_all=全选 +input.menu.quick_input=快捷输入 # mode @@ -224,6 +232,11 @@ settings.ligature.from = 从 settings.ligature.to = 到 settings.ligature.add = 添加规则 settings.ligature.sample = 例如:从 * 到 ※ ,输入 \\* 会自动变成 ※ +## quick input +settings.quick_input.title = 快捷输入 +settings.quick_input.hint = 没有短语,你可以创建一个 +settings.quick_input.add = 添加短语 +settings.quick_input.sample = 编辑时右键编辑框便可使用快捷输入 ## mode settings.mode.title = 模式 settings.mode.scale.label = 切换到新图片时的缩放比例 @@ -244,6 +257,9 @@ settings.other.meo_default = 使用喵版翻译文件作为默认保存格式 settings.other.template.enable = 导出翻译文件时使用预设模板 settings.other.template.hint = 可用的变量:%FILE% 文件名称,%DIR% 目录名称,%PROJECT% 项目目录名称\n不能含有 * : ? < > | / " \\ settings.other.template.default = %FILE% 翻译:XXX +settings.other.Translate_keys.enable = 使用自定义的百度翻译密钥(用于繁简体转换) +settings.other.Translate_keys.key = 密钥 +settings.other.Translate_keys.app_id = APP ID # logs logs.title = Logs diff --git a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties index 48d2ce5..e590ff9 100644 --- a/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties +++ b/src/main/resources/ink/meodinger/lpfx/Lang_zh_TW.properties @@ -88,6 +88,15 @@ context.copy_label_text = 複製文本 context.paste_label_text = 粘貼文本 context.delete_label = 删除 +## input +input.menu.undo=還原 +input.menu.redo=重做 +input.menu.cut=剪下 +input.menu.copy=複製 +input.menu.paste=貼上 +input.menu.delete_selection=刪除 +input.menu.select_all=全選 +input.menu.quick_input=快捷输入 # mode mode.work.input = 輸入模式 @@ -223,6 +232,11 @@ settings.ligature.from = 從 settings.ligature.to = 到 settings.ligature.add = 添加規則 settings.ligature.sample = 例如:從 * 到 ※ ,輸入 \\* 會自動變成 ※ +## quick input +settings.quick_input.title = 快捷輸入 +settings.quick_input.hint = 沒有短語,你可以創建一個 +settings.quick_input.add = 添加短語 +settings.quick_input.sample = 編輯時右鍵編輯框便可使用快捷輸入 ## mode settings.mode.title = 模式 settings.mode.scale.label = 切換到新圖片時的縮放比例 @@ -243,6 +257,9 @@ settings.other.meo_default = 使用喵版翻譯檔案作為默認保存格式 settings.other.template.enable = 匯出翻譯檔案時使用預設範本 settings.other.template.hint = 可用的變數:%FILE% 檔案名稱,%DIR% 目錄名稱,%PROJECT% 項目目錄名稱\n不能含有 * : ? < > | / " \\ settings.other.template.default = %FILE% 翻譯:XXX +settings.other.Translate_keys.enable = 使用自定義的百度翻譯密鑰(用於繁簡體轉換) +settings.other.Translate_keys.key = 密鑰 +settings.other.Translate_keys.app_id = APP ID # logs logs.title = Logs From 5a96f962c780119090d6cde494aae087559ccf8c Mon Sep 17 00:00:00 2001 From: Ye Ding <“kanaumachi@gmail.com”> Date: Thu, 17 Oct 2024 00:23:25 +0900 Subject: [PATCH 25/28] release 2.3.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f6577f0..839fc0f 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ ink.meodinger lpfx - 2.3.3 + 2.3.4 jar lpfx From 08b6fb9aef4f67926b548258acb71366056911d1 Mon Sep 17 00:00:00 2001 From: Yeding Date: Sat, 19 Oct 2024 22:54:05 +0900 Subject: [PATCH 26/28] feature: now it will try to load the properties of the old version if it no find the properties of current version --- CHANGELOG.md | 1 + .../kotlin/ink/meodinger/lpfx/io/Translate.kt | 2 +- .../lpfx/options/AbstractProperties.kt | 8 ++-- .../ink/meodinger/lpfx/options/Options.kt | 20 +++++++- .../ink/meodinger/lpfx/options/Settings.kt | 46 ++++++++++++++++++- .../kotlin/ink/meodinger/lpfx/util/CUtil.kt | 24 ++++++++++ 6 files changed, 95 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd712b6..d965c7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Add - 选中右键树状图中的Label支持移动序号 - 图片区添加QW切换图片的快捷键 - 添加百度翻译key设置用于配置繁简体转换 + - 现在更新版本会尝试加载旧版本的配置文件 Fix diff --git a/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt b/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt index 350734b..a81ba7e 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/io/Translate.kt @@ -36,7 +36,7 @@ private fun query(q: String, from: String, to: String): String { val key = if (Settings.useCustomBaiduKey) Settings.baiduTransLateKey else KEY val appId = if (Settings.useCustomBaiduKey) Settings.baiduTransLateAppId else ID val sign = md5("$appId$q$salt$key").lowercase() - Logger.info(Settings.baiduTransLateAppId+ ","+Settings.baiduTransLateKey, "Controller") + Logger.info("TranslateAppId:${Settings.baiduTransLateAppId},TranslateAppId:${Settings.baiduTransLateKey}", "Translate") return "$ROOT?q=${URLEncoder.encode(q, utf8Charset)}&from=$from&to=$to&appid=$appId&salt=$salt&sign=$sign" } diff --git a/src/main/kotlin/ink/meodinger/lpfx/options/AbstractProperties.kt b/src/main/kotlin/ink/meodinger/lpfx/options/AbstractProperties.kt index 74091fb..004ea87 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/options/AbstractProperties.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/options/AbstractProperties.kt @@ -53,9 +53,9 @@ abstract class AbstractProperties(val name: String, val path: Path) { while (index < lines.size && lines[index].startsWith(CProperty.LIST_SEPARATOR)) { propList.add(lines[index++].substring(1)) } - instance[prop[0]].set(propList) + instance.find(prop[0])?.set(propList) } else { - instance[prop[0]].set(prop[1]) + instance.find(prop[0])?.set(prop[1]) } } } catch { e: IndexOutOfBoundsException -> @@ -105,7 +105,9 @@ abstract class AbstractProperties(val name: String, val path: Path) { properties.addAll(default.map(CProperty::copy)) } - operator fun get(key: String): CProperty = properties.first { it.key == key } + operator fun get(key: String): CProperty = properties.first() { it.key == key } + + fun find(key: String): CProperty? = properties.firstOrNull() { it.key == key } override fun toString(): String = properties.joinToString(", \n", transform = CProperty::toString) diff --git a/src/main/kotlin/ink/meodinger/lpfx/options/Options.kt b/src/main/kotlin/ink/meodinger/lpfx/options/Options.kt index 85f6b45..2953203 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/options/Options.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/options/Options.kt @@ -5,6 +5,7 @@ import ink.meodinger.lpfx.V import ink.meodinger.lpfx.component.dialog.showError import ink.meodinger.lpfx.component.dialog.showException import ink.meodinger.lpfx.get +import ink.meodinger.lpfx.util.Version import ink.meodinger.lpfx.util.doNothing import ink.meodinger.lpfx.util.file.transfer import ink.meodinger.lpfx.util.once @@ -89,7 +90,11 @@ object Options { private fun loadProperties(instance: AbstractProperties) { // Unknown properties will be defaults, so we just need to // make sure the file we will load exists. - if (Files.notExists(instance.path)) Files.createFile(instance.path) + if (Files.notExists(instance.path)) { + val file = Files.createFile(instance.path).toFile() + findOldProperties(instance.path)?.let { transfer(it,file) } + Logger.info("Loaded ${instance.name} in old version to use for the new version ", "Options") + } try { instance.load() @@ -97,10 +102,12 @@ object Options { } catch (e: Throwable) { // Copy invalid properties file to temp, prepare for sending val tempFile = createTempFile().toFile() + Logger.info("tempFile: ${tempFile.path}", "Options") try { transfer(instance.path.toFile(), tempFile) } catch (e: Throwable) { doNothing() + Logger.error("create ${instance.name} properties failed, using default", "Options") } finally { tempFile.deleteOnExit() } @@ -116,6 +123,17 @@ object Options { showException(null, e, tempFile) } } + // find the old Properties to use for the new version + private fun findOldProperties(nowPropsPath :Path) :File?{ + val parentDir = nowPropsPath.parent.parent + if(Files.list(parentDir).count() <=1) return null + val oldPropsPath = Files.list(parentDir) + .toList() + .filter { Files.isDirectory(it) and (it.fileName.toString() != V.toString()) } + .maxWithOrNull(compareBy { Version(it.fileName.toString())}) + + return oldPropsPath?.resolve(nowPropsPath.fileName)?.toFile() + } private fun saveProperties(instance: AbstractProperties) { try { diff --git a/src/main/kotlin/ink/meodinger/lpfx/options/Settings.kt b/src/main/kotlin/ink/meodinger/lpfx/options/Settings.kt index eabd45d..3afc4d1 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/options/Settings.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/options/Settings.kt @@ -37,6 +37,7 @@ object Settings : AbstractProperties("Settings", Options.settings) { const val DefaultGroupColorHexList = "DefaultGroupColorList" const val IsGroupCreateOnNewTrans = "IsGroupCreateOnNew" const val LigatureRules = "LigatureRules" + const val QuickInputTexts = "QuickInputTexts" const val ViewModes = "ViewMode" const val NewPictureScale = "ScaleOnNewPicture" const val UseWheelToScale = "UseWheelToScale" @@ -51,6 +52,9 @@ object Settings : AbstractProperties("Settings", Options.settings) { const val UseExportNameTemplate = "UseExportNameTemplate" const val ExportNameTemplate = "ExportNameTemplate" const val LogLevel = "LogLevel" + const val UseCustomBaiduKey = "UseCustomBaiduKey" + const val BaiduTransLateKey = "BaiduTransLateKey" + const val BaiduTransLateAppId = "BaiduTransLateAppId" // ----- Default ----- // @@ -70,6 +74,19 @@ object Settings : AbstractProperties("Settings", Options.settings) { "cc" to "◎", "*" to "※", ), + CProperty(QuickInputTexts, + "「", + "」", + "『", + "』", + "⭐", + "♢", + "♡", + "♪", + "◎", + "※", + "♥", + ), CProperty(ViewModes, ViewMode.IndexMode.ordinal, ViewMode.GroupMode.ordinal), CProperty(NewPictureScale, CLabelPane.NewPictureScale.DEFAULT.ordinal), CProperty(UseWheelToScale, false), @@ -84,6 +101,9 @@ object Settings : AbstractProperties("Settings", Options.settings) { CProperty(UseExportNameTemplate, false), CProperty(ExportNameTemplate, I18N["settings.other.template.default"]), CProperty(LogLevel, Logger.LogLevel.INFO.ordinal), + CProperty(UseCustomBaiduKey, false), + CProperty(BaiduTransLateKey, "lkjooeJUgW0spOctSbZb"), + CProperty(BaiduTransLateAppId, "20200730000529751"), ) private val defaultGroupNameListProperty: ListProperty = SimpleListProperty() @@ -102,6 +122,11 @@ object Settings : AbstractProperties("Settings", Options.settings) { fun ligatureRulesProperty(): ListProperty> = ligatureRulesProperty var ligatureRules: ObservableList> by ligatureRulesProperty + val quickInputTextsProperty: ListProperty = SimpleListProperty() + fun quickInputTextsProperty(): ListProperty = quickInputTextsProperty + var quickInputTexts: ObservableList by quickInputTextsProperty + + private val viewModesProperty: ListProperty = SimpleListProperty() fun viewModesProperty(): ListProperty = viewModesProperty var viewModes: ObservableList by viewModesProperty @@ -158,6 +183,18 @@ object Settings : AbstractProperties("Settings", Options.settings) { fun logLevelProperty(): ObjectProperty = logLevelProperty var logLevel: Logger.LogLevel by logLevelProperty + private val useCustomBaiduKeyProperty: BooleanProperty = SimpleBooleanProperty() + fun useCustomBaiduKeyProperty(): BooleanProperty = useCustomBaiduKeyProperty + var useCustomBaiduKey: Boolean by useCustomBaiduKeyProperty + + private val baiduTransLateKeyProperty: StringProperty = SimpleStringProperty() + fun baiduTransLateKeyProperty(): StringProperty = baiduTransLateKeyProperty + var baiduTransLateKey: String by baiduTransLateKeyProperty + + private val baiduTransLateAppIdProperty: StringProperty = SimpleStringProperty() + fun baiduTransLateAppIdProperty(): StringProperty = baiduTransLateAppIdProperty + var baiduTransLateAppId: String by baiduTransLateAppIdProperty + init { useDefault() } @@ -169,6 +206,7 @@ object Settings : AbstractProperties("Settings", Options.settings) { defaultGroupColorHexList = FXCollections.observableList(this[DefaultGroupColorHexList].asStringList()) isGroupCreateOnNewTransList = FXCollections.observableList(this[IsGroupCreateOnNewTrans].asBooleanList()) ligatureRules = FXCollections.observableList(this[LigatureRules].asPairList()) + quickInputTexts = FXCollections.observableList(this[QuickInputTexts].asStringList()) viewModes = FXCollections.observableList(this[ViewModes].asIntegerList().map(ViewMode.values()::get)) newPictureScalePicture = CLabelPane.NewPictureScale.values()[this[NewPictureScale].asInteger()] useWheelToScale = this[UseWheelToScale].asBoolean() @@ -183,6 +221,9 @@ object Settings : AbstractProperties("Settings", Options.settings) { useExportNameTemplate = this[UseExportNameTemplate].asBoolean() exportNameTemplate = this[ExportNameTemplate].asString() logLevel = Logger.LogLevel.values()[this[LogLevel].asInteger()] + useCustomBaiduKey = this[UseCustomBaiduKey].asBoolean() + baiduTransLateKey = this[BaiduTransLateKey].asString() + baiduTransLateAppId = this[BaiduTransLateAppId].asString() } @Throws(IOException::class) @@ -191,6 +232,7 @@ object Settings : AbstractProperties("Settings", Options.settings) { this[DefaultGroupColorHexList].set(defaultGroupColorHexList) this[IsGroupCreateOnNewTrans] .set(isGroupCreateOnNewTransList) this[LigatureRules] .set(ligatureRules) + this[QuickInputTexts] .set(quickInputTexts) this[ViewModes] .set(viewModes.map(Enum<*>::ordinal)) this[NewPictureScale] .set(newPictureScalePicture.ordinal) this[UseWheelToScale] .set(useWheelToScale) @@ -205,7 +247,9 @@ object Settings : AbstractProperties("Settings", Options.settings) { this[UseExportNameTemplate] .set(useExportNameTemplate) this[ExportNameTemplate] .set(exportNameTemplate) this[LogLevel] .set(logLevel.ordinal) - + this[UseCustomBaiduKey] .set(useCustomBaiduKey) + this[BaiduTransLateKey] .set(baiduTransLateKey) + this[BaiduTransLateAppId] .set(baiduTransLateAppId) save(this) } diff --git a/src/main/kotlin/ink/meodinger/lpfx/util/CUtil.kt b/src/main/kotlin/ink/meodinger/lpfx/util/CUtil.kt index 3945852..f63a990 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/util/CUtil.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/util/CUtil.kt @@ -42,8 +42,27 @@ data class Version(val a: Int, val b: Int, val c: Int): Comparable { return Version(l[0].substring(1).toInt(), l[1].toInt(), l[2].toInt()) } + /** + * Construct a Version from a String in the format "vX.Y.Z" + */ + operator fun invoke(version: String): Version { + val trimmedVersion = version.trim() + if (!trimmedVersion.startsWith("v")) return V0 + val parts = trimmedVersion.substring(1).split(".") + + if (parts.size != 3) return V0 // 确保有三部分 + val (major, minor, patch) = parts.map { it.toIntOrNull() } // 转换为整数 + + return if (major != null && minor != null && patch != null) { + Version(major, minor, patch) + } else { + V0 // 如果转换失败,返回 V0 + } + } } + + init { check(a) check(b) @@ -53,9 +72,14 @@ data class Version(val a: Int, val b: Int, val c: Int): Comparable { override fun toString(): String = "v$a.$b.$c" override operator fun compareTo(other: Version): Int { + return this - other + } + + operator fun minus(other: Version): Int { return (this.a - other.a) * 10000 + (this.b - other.b) * 100 + (this.c - other.c) } + } /** From a7e4de768ba5399c95eb15ef2ed2e482d783abc3 Mon Sep 17 00:00:00 2001 From: Yeding Date: Sat, 19 Oct 2024 23:20:56 +0900 Subject: [PATCH 27/28] roll back the version for original --- script/jpackage/build.bat | 4 +--- src/main/kotlin/ink/meodinger/lpfx/Constants.kt | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/script/jpackage/build.bat b/script/jpackage/build.bat index ccb4e3b..d5b50ba 100644 --- a/script/jpackage/build.bat +++ b/script/jpackage/build.bat @@ -6,9 +6,7 @@ rd /S /Q ".\LabelPlusFX" set MODULES="%DIR%\target\build" set ICON="%DIR%\images\icons\cat.ico" -jpackage --verbose --type app-image --app-version 2.3.4 --copyright "Meodinger Tech (C) 2022" --name LabelPlusFX --icon %ICON% --dest . --module-path %MODULES% --add-modules lpfx,jdk.crypto.cryptoki --module lpfx/ink.meodinger.lpfx.LauncherKt --java-options "-Dprism.maxvram=2G" +jpackage --verbose --type app-image --app-version 2.3.3 --copyright "Meodinger Tech (C) 2022" --name LabelPlusFX --icon %ICON% --dest . --module-path %MODULES% --add-modules lpfx,jdk.crypto.cryptoki --module lpfx/ink.meodinger.lpfx.LauncherKt --java-options "-Dprism.maxvram=2G" echo: echo All completed, remember to copy dlls! - -pause \ No newline at end of file diff --git a/src/main/kotlin/ink/meodinger/lpfx/Constants.kt b/src/main/kotlin/ink/meodinger/lpfx/Constants.kt index e221996..c9897ed 100644 --- a/src/main/kotlin/ink/meodinger/lpfx/Constants.kt +++ b/src/main/kotlin/ink/meodinger/lpfx/Constants.kt @@ -16,7 +16,7 @@ import java.io.File /** * Current Version */ -val V: Version = Version(2, 3, 4) +val V: Version = Version(2, 3, 3) /** * Default Filename Placeholder. It's Esperanto! From 2fbb928f562d27b582e78b38bdd6c141fcdbe318 Mon Sep 17 00:00:00 2001 From: Yeding Date: Sun, 20 Oct 2024 00:26:37 +0900 Subject: [PATCH 28/28] add the chinese version for readme --- README.md | 1 + README_ZH.md | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 README_ZH.md diff --git a/README.md b/README.md index 9613346..c0a8fc8 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ +[简体中文](/README_ZH.md) | English

diff --git a/README_ZH.md b/README_ZH.md new file mode 100644 index 0000000..5db6038 --- /dev/null +++ b/README_ZH.md @@ -0,0 +1,130 @@ + + + + + +简体中文 | [English](/README.md) +
+

+ + Logo + +

Label Plus FX

+

+ 一个跨平台的Label Plus +
+
+ 用户手册 + · + 反馈问题 + · + 提交建议 +

+

+ + + +
+

目录

+
    +
  1. + 关于本项目 +
  2. +
  3. + 开始 + +
  4. +
  5. 说明
  6. +
  7. 许可协议
  8. +
  9. 联系方式
  10. +
+
+ + + +## 关于本项目 + +[![Product Screen Shot][product-screenshot]]() + +本项目受到 [LabelPlus](https://noodlefighter.com/label_plus/)的启发。 + + + +## 开始 + +复制本项目并启动需要以下几个简单的步骤 + +### 环境 + + * [Liberica JDK 17 (完整版本)](https://bell-sw.com/pages/downloads/#/java-17-lts%20/%20current) : 用于主应用程序; + + * [可选] [Visual Studio 2019](https://visualstudio.microsoft.com/zh-hans/downloads/) : 用于Windows IME JNI接口; + + +### 启动步骤 + +1.克隆仓库 + ```sh + git clone https://github.com/Meodinger/LabelPlusFX.git + ``` +2. 运行Maven命令 `package` + +3. 运行脚本, `link.bat` `build.bat` 都可以 + +4. 对于Windows用户, 构建封装器库 `IMEWrapper` 然后复制 `IMEInterface.dll` 和 `IMEWrapper.dll` 到 `LabelPlusFX.exe` (使用`jpackage`)或 `runtime\java.exe`(使用`jlink`) 所在的文件夹下. + +> 如果不想使用Windows IME JNI接口, 可以使用 `run.bat --disable-jni` 或`LabelPlusFX.exe --disable-jni`方式启动 + +> 在IDE中运行LPFX, 可以执行 `exec:java@run` 命令 + + +## 说明 + +Label Plus FX的功能设计基于 [LabelPlus](https://noodlefighter.com/label_plus/) + +更多示例,请参考用户手册和Wiki [User Manual](https://www.kdocs.cn/l/seRSJCKVOn0Y) 和 [Wiki](https://github.com/Meodinger/LabelPlusFX/wiki) + + + +## 贡献 + +开源社区因贡献而变得如此美好,充满学习、启发和创造。非常感谢您所做的**任何贡献** + +1. Fork项目 +2. 创建功能分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m '添加了一些很棒的改进'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 发起拉取请求 + + + +## 许可协议 + +根据AGPLv3许可证分发。有关更多信息,请参见`LICENSE`页面。 + + + +## 联系方式 + +Meodinger Wang - [@Meodinger_Wang](https://twitter.com/Meodinger_Wang) - meodinger@qq.com + +项目链接: [https://github.com/Meodinger/LabelPlusFX](https://github.com/Meodinger/LabelPlusFX) + + + +## 赞助 + + + Aifadian + + +[product-screenshot]: https://s2.loli.net/2022/02/04/2H7bguJ9rcyBjUO.png \ No newline at end of file