From c6220d1e1615b7b4f8c2efa8ccccb913de33506a Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Mon, 4 Apr 2022 13:52:35 +0800 Subject: [PATCH] ctlIME // Extract all menu-related contents to a standalone file. - Use a standalone swift file to manage the composition of the menu itself and its subcommands. --- Source/Modules/IME.swift | 29 ++ .../Modules/IMEModules/ctlInputMethod.swift | 273 ----------------- .../IMEModules/ctlInputMethod_Menu.swift | 282 ++++++++++++++++++ vChewing.xcodeproj/project.pbxproj | 4 + 4 files changed, 315 insertions(+), 273 deletions(-) create mode 100644 Source/Modules/IMEModules/ctlInputMethod_Menu.swift diff --git a/Source/Modules/IME.swift b/Source/Modules/IME.swift index 72d69719..2e60ec79 100644 --- a/Source/Modules/IME.swift +++ b/Source/Modules/IME.swift @@ -31,6 +31,11 @@ import Cocoa // MARK: - 開關判定當前應用究竟是? @objc static var areWeUsingOurOwnPhraseEditor: Bool = false + // MARK: - 自 ctlInputMethod 讀取當前輸入法的簡繁體模式 + static func getInputMode() -> InputMode { + return ctlInputMethod.currentKeyHandler.inputMode + } + // MARK: - Print debug information to the console. @objc static func prtDebugIntel(_ strPrint: String) { if mgrPrefs.isDebugModeEnabled { @@ -76,6 +81,30 @@ import Cocoa return false } + // MARK: - Open a phrase data file. + static func openPhraseFile(userFileAt path: String) { + func checkIfUserFilesExist() -> Bool { + if !mgrLangModel.checkIfUserLanguageModelFilesExist() { + let content = String( + format: NSLocalizedString( + "Please check the permission at \"%@\".", comment: ""), + mgrLangModel.dataFolderPath(isDefaultFolder: false)) + ctlNonModalAlertWindow.shared.show( + title: NSLocalizedString("Unable to create the user phrase file.", comment: ""), + content: content, confirmButtonTitle: NSLocalizedString("OK", comment: ""), + cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) + NSApp.setActivationPolicy(.accessory) + return false + } + return true + } + + if !checkIfUserFilesExist() { + return + } + NSWorkspace.shared.openFile(path, withApplication: "vChewingPhraseEditor") + } + // MARK: - Trash a file if it exists. @discardableResult static func trashTargetIfExists(_ path: String) -> Bool { do { diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index 09ae6e20..ef75f81d 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -27,12 +27,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa import InputMethodKit -extension Bool { - fileprivate var state: NSControl.StateValue { - self ? .on : .off - } -} - private let kMinKeyLabelSize: CGFloat = 10 private var ctlCandidateCurrent: ctlCandidate? @@ -82,118 +76,6 @@ class ctlInputMethod: IMKInputController { keyHandler.delegate = self } - override func menu() -> NSMenu! { - let optionKeyPressed = NSEvent.modifierFlags.contains(.option) - - let menu = NSMenu(title: "Input Method Menu") - - let useSCPCTypingModeItem = menu.addItem( - withTitle: NSLocalizedString("Per-Char Select Mode", comment: ""), - action: #selector(toggleSCPCTypingMode(_:)), keyEquivalent: "P") - useSCPCTypingModeItem.keyEquivalentModifierMask = [.command, .control] - useSCPCTypingModeItem.state = mgrPrefs.useSCPCTypingMode.state - - let useCNS11643SupportItem = menu.addItem( - withTitle: NSLocalizedString("CNS11643 Mode", comment: ""), - action: #selector(toggleCNS11643Enabled(_:)), keyEquivalent: "L") - useCNS11643SupportItem.keyEquivalentModifierMask = [.command, .control] - useCNS11643SupportItem.state = mgrPrefs.cns11643Enabled.state - - if keyHandler.inputMode == InputMode.imeModeCHT { - let chineseConversionItem = menu.addItem( - withTitle: NSLocalizedString("Force KangXi Writing", comment: ""), - action: #selector(toggleChineseConverter(_:)), keyEquivalent: "K") - chineseConversionItem.keyEquivalentModifierMask = [.command, .control] - chineseConversionItem.state = mgrPrefs.chineseConversionEnabled.state - - let shiftJISConversionItem = menu.addItem( - withTitle: NSLocalizedString("JIS Shinjitai Output", comment: ""), - action: #selector(toggleShiftJISShinjitaiOutput(_:)), keyEquivalent: "J") - shiftJISConversionItem.keyEquivalentModifierMask = [.command, .control] - shiftJISConversionItem.state = mgrPrefs.shiftJISShinjitaiOutputEnabled.state - } - - let halfWidthPunctuationItem = menu.addItem( - withTitle: NSLocalizedString("Half-Width Punctuation Mode", comment: ""), - action: #selector(toggleHalfWidthPunctuation(_:)), keyEquivalent: "H") - halfWidthPunctuationItem.keyEquivalentModifierMask = [.command, .control] - halfWidthPunctuationItem.state = mgrPrefs.halfWidthPunctuationEnabled.state - - let userAssociatedPhrasesItem = menu.addItem( - withTitle: NSLocalizedString("Per-Char Associated Phrases", comment: ""), - action: #selector(toggleAssociatedPhrasesEnabled(_:)), keyEquivalent: "O") - userAssociatedPhrasesItem.keyEquivalentModifierMask = [.command, .control] - userAssociatedPhrasesItem.state = mgrPrefs.associatedPhrasesEnabled.state - - if optionKeyPressed { - let phaseReplacementItem = menu.addItem( - withTitle: NSLocalizedString("Use Phrase Replacement", comment: ""), - action: #selector(togglePhraseReplacement(_:)), keyEquivalent: "") - phaseReplacementItem.state = mgrPrefs.phraseReplacementEnabled.state - - let toggleSymbolInputItem = menu.addItem( - withTitle: NSLocalizedString("Symbol & Emoji Input", comment: ""), - action: #selector(toggleSymbolEnabled(_:)), keyEquivalent: "") - toggleSymbolInputItem.state = mgrPrefs.symbolInputEnabled.state - } - - menu.addItem(NSMenuItem.separator()) // --------------------- - - menu.addItem( - withTitle: NSLocalizedString("Open User Data Folder", comment: ""), - action: #selector(openUserDataFolder(_:)), keyEquivalent: "") - menu.addItem( - withTitle: NSLocalizedString("Edit User Phrases…", comment: ""), - action: #selector(openUserPhrases(_:)), keyEquivalent: "") - - if optionKeyPressed { - menu.addItem( - withTitle: NSLocalizedString("Edit Excluded Phrases…", comment: ""), - action: #selector(openExcludedPhrases(_:)), keyEquivalent: "") - menu.addItem( - withTitle: NSLocalizedString("Edit Phrase Replacement Table…", comment: ""), - action: #selector(openPhraseReplacement(_:)), keyEquivalent: "") - menu.addItem( - withTitle: NSLocalizedString("Edit Associated Phrases…", comment: ""), - action: #selector(openAssociatedPhrases(_:)), keyEquivalent: "") - menu.addItem( - withTitle: NSLocalizedString("Edit User Symbol & Emoji Data…", comment: ""), - action: #selector(openUserSymbols(_:)), keyEquivalent: "") - } - - if optionKeyPressed || !mgrPrefs.shouldAutoReloadUserDataFiles { - menu.addItem( - withTitle: NSLocalizedString("Reload User Phrases", comment: ""), - action: #selector(reloadUserPhrases(_:)), keyEquivalent: "") - } - - menu.addItem(NSMenuItem.separator()) // --------------------- - - menu.addItem( - withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), - action: #selector(showPreferences(_:)), keyEquivalent: "") - if !optionKeyPressed { - menu.addItem( - withTitle: NSLocalizedString("Check for Updates…", comment: ""), - action: #selector(checkForUpdate(_:)), keyEquivalent: "") - } - menu.addItem( - withTitle: NSLocalizedString("Reboot vChewing…", comment: ""), - action: #selector(selfTerminate(_:)), keyEquivalent: "") - menu.addItem( - withTitle: NSLocalizedString("About vChewing…", comment: ""), - action: #selector(showAbout(_:)), keyEquivalent: "") - if optionKeyPressed { - menu.addItem( - withTitle: NSLocalizedString("Uninstall vChewing…", comment: ""), - action: #selector(selfUninstall(_:)), keyEquivalent: "") - } - - // NSMenu 會阻止任何 modified key 相關的訊號傳回輸入法,所以咱們在此重設鍵盤佈局 - setKeyLayout() - return menu - } - // MARK: - IMKStateSetting protocol methods override func activateServer(_ client: Any!) { @@ -285,161 +167,6 @@ class ctlInputMethod: IMKInputController { } return result } - - // MARK: - Menu Items - - @objc override func showPreferences(_ sender: Any?) { - (NSApp.delegate as? AppDelegate)?.showPreferences() - NSApp.activate(ignoringOtherApps: true) - } - - @objc func toggleSCPCTypingMode(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("Per-Char Select Mode", comment: ""), "\n", - mgrPrefs.toggleSCPCTypingModeEnabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func toggleChineseConverter(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("Force KangXi Writing", comment: ""), "\n", - mgrPrefs.toggleChineseConversionEnabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func toggleShiftJISShinjitaiOutput(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("JIS Shinjitai Output", comment: ""), "\n", - mgrPrefs.toggleShiftJISShinjitaiOutputEnabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func toggleHalfWidthPunctuation(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("Half-Width Punctuation Mode", comment: ""), - "\n", - mgrPrefs.toggleHalfWidthPunctuationEnabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func toggleCNS11643Enabled(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("CNS11643 Mode", comment: ""), "\n", - mgrPrefs.toggleCNS11643Enabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func toggleSymbolEnabled(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("Symbol & Emoji Input", comment: ""), "\n", - mgrPrefs.toggleSymbolInputEnabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func toggleAssociatedPhrasesEnabled(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("Per-Char Associated Phrases", comment: ""), - "\n", - mgrPrefs.toggleAssociatedPhrasesEnabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func togglePhraseReplacement(_ sender: Any?) { - NotifierController.notify( - message: String( - format: "%@%@%@", NSLocalizedString("Use Phrase Replacement", comment: ""), "\n", - mgrPrefs.togglePhraseReplacementEnabled() - ? NSLocalizedString("NotificationSwitchON", comment: "") - : NSLocalizedString("NotificationSwitchOFF", comment: ""))) - } - - @objc func selfUninstall(_ sender: Any?) { - (NSApp.delegate as? AppDelegate)?.selfUninstall() - } - - @objc func selfTerminate(_ sender: Any?) { - NSApp.terminate(nil) - } - - @objc func checkForUpdate(_ sender: Any?) { - (NSApp.delegate as? AppDelegate)?.checkForUpdate(forced: true) - } - - private func open(userFileAt path: String) { - func checkIfUserFilesExist() -> Bool { - if !mgrLangModel.checkIfUserLanguageModelFilesExist() { - let content = String( - format: NSLocalizedString( - "Please check the permission at \"%@\".", comment: ""), - mgrLangModel.dataFolderPath(isDefaultFolder: false)) - ctlNonModalAlertWindow.shared.show( - title: NSLocalizedString("Unable to create the user phrase file.", comment: ""), - content: content, confirmButtonTitle: NSLocalizedString("OK", comment: ""), - cancelButtonTitle: nil, cancelAsDefault: false, delegate: nil) - NSApp.setActivationPolicy(.accessory) - return false - } - return true - } - - if !checkIfUserFilesExist() { - return - } - NSWorkspace.shared.openFile(path, withApplication: "vChewingPhraseEditor") - } - - @objc func openUserPhrases(_ sender: Any?) { - open(userFileAt: mgrLangModel.userPhrasesDataPath(keyHandler.inputMode)) - } - - @objc func openUserDataFolder(_ sender: Any?) { - if !mgrLangModel.checkIfUserDataFolderExists() { - return - } - NSWorkspace.shared.openFile( - mgrLangModel.dataFolderPath(isDefaultFolder: false), withApplication: "Finder") - } - - @objc func openExcludedPhrases(_ sender: Any?) { - open(userFileAt: mgrLangModel.excludedPhrasesDataPath(keyHandler.inputMode)) - } - - @objc func openUserSymbols(_ sender: Any?) { - open(userFileAt: mgrLangModel.userSymbolDataPath(keyHandler.inputMode)) - } - - @objc func openPhraseReplacement(_ sender: Any?) { - open(userFileAt: mgrLangModel.phraseReplacementDataPath(keyHandler.inputMode)) - } - - @objc func openAssociatedPhrases(_ sender: Any?) { - open(userFileAt: mgrLangModel.userAssociatedPhrasesDataPath(keyHandler.inputMode)) - } - - @objc func reloadUserPhrases(_ sender: Any?) { - mgrLangModel.loadUserPhrases() - mgrLangModel.loadUserPhraseReplacement() - } - - @objc func showAbout(_ sender: Any?) { - (NSApp.delegate as? AppDelegate)?.showAbout() - NSApp.activate(ignoringOtherApps: true) - } - } // MARK: - State Handling diff --git a/Source/Modules/IMEModules/ctlInputMethod_Menu.swift b/Source/Modules/IMEModules/ctlInputMethod_Menu.swift new file mode 100644 index 00000000..a9152e56 --- /dev/null +++ b/Source/Modules/IMEModules/ctlInputMethod_Menu.swift @@ -0,0 +1,282 @@ +// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License). +// All possible vChewing-specific modifications are of: +// (c) 2021 and onwards The vChewing Project (MIT-NTL License). +/* +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +1. The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +2. No trademark license is granted to use the trade names, trademarks, service +marks, or product names of Contributor, except as required to fulfill notice +requirements above. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import Cocoa + +extension Bool { + fileprivate var state: NSControl.StateValue { + self ? .on : .off + } +} + +// MARK: - IME Menu Manager +// 因為選單部分的內容又臭又長,所以就單獨拉到一個檔案內管理了。 + +extension ctlInputMethod { + override func menu() -> NSMenu! { + let optionKeyPressed = NSEvent.modifierFlags.contains(.option) + + let menu = NSMenu(title: "Input Method Menu") + + let useSCPCTypingModeItem = menu.addItem( + withTitle: NSLocalizedString("Per-Char Select Mode", comment: ""), + action: #selector(toggleSCPCTypingMode(_:)), keyEquivalent: "P") + useSCPCTypingModeItem.keyEquivalentModifierMask = [.command, .control] + useSCPCTypingModeItem.state = mgrPrefs.useSCPCTypingMode.state + + let userAssociatedPhrasesItem = menu.addItem( + withTitle: NSLocalizedString("Per-Char Associated Phrases", comment: ""), + action: #selector(toggleAssociatedPhrasesEnabled(_:)), keyEquivalent: "O") + userAssociatedPhrasesItem.keyEquivalentModifierMask = [.command, .control] + userAssociatedPhrasesItem.state = mgrPrefs.associatedPhrasesEnabled.state + + let useCNS11643SupportItem = menu.addItem( + withTitle: NSLocalizedString("CNS11643 Mode", comment: ""), + action: #selector(toggleCNS11643Enabled(_:)), keyEquivalent: "L") + useCNS11643SupportItem.keyEquivalentModifierMask = [.command, .control] + useCNS11643SupportItem.state = mgrPrefs.cns11643Enabled.state + + if IME.getInputMode() == InputMode.imeModeCHT { + let chineseConversionItem = menu.addItem( + withTitle: NSLocalizedString("Force KangXi Writing", comment: ""), + action: #selector(toggleChineseConverter(_:)), keyEquivalent: "K") + chineseConversionItem.keyEquivalentModifierMask = [.command, .control] + chineseConversionItem.state = mgrPrefs.chineseConversionEnabled.state + + let shiftJISConversionItem = menu.addItem( + withTitle: NSLocalizedString("JIS Shinjitai Output", comment: ""), + action: #selector(toggleShiftJISShinjitaiOutput(_:)), keyEquivalent: "J") + shiftJISConversionItem.keyEquivalentModifierMask = [.command, .control] + shiftJISConversionItem.state = mgrPrefs.shiftJISShinjitaiOutputEnabled.state + } + + let halfWidthPunctuationItem = menu.addItem( + withTitle: NSLocalizedString("Half-Width Punctuation Mode", comment: ""), + action: #selector(toggleHalfWidthPunctuation(_:)), keyEquivalent: "H") + halfWidthPunctuationItem.keyEquivalentModifierMask = [.command, .control] + halfWidthPunctuationItem.state = mgrPrefs.halfWidthPunctuationEnabled.state + + if optionKeyPressed { + let phaseReplacementItem = menu.addItem( + withTitle: NSLocalizedString("Use Phrase Replacement", comment: ""), + action: #selector(togglePhraseReplacement(_:)), keyEquivalent: "") + phaseReplacementItem.state = mgrPrefs.phraseReplacementEnabled.state + + let toggleSymbolInputItem = menu.addItem( + withTitle: NSLocalizedString("Symbol & Emoji Input", comment: ""), + action: #selector(toggleSymbolEnabled(_:)), keyEquivalent: "") + toggleSymbolInputItem.state = mgrPrefs.symbolInputEnabled.state + } + + menu.addItem(NSMenuItem.separator()) // --------------------- + + menu.addItem( + withTitle: NSLocalizedString("Open User Data Folder", comment: ""), + action: #selector(openUserDataFolder(_:)), keyEquivalent: "") + menu.addItem( + withTitle: NSLocalizedString("Edit User Phrases…", comment: ""), + action: #selector(openUserPhrases(_:)), keyEquivalent: "") + + if optionKeyPressed { + menu.addItem( + withTitle: NSLocalizedString("Edit Excluded Phrases…", comment: ""), + action: #selector(openExcludedPhrases(_:)), keyEquivalent: "") + menu.addItem( + withTitle: NSLocalizedString("Edit Phrase Replacement Table…", comment: ""), + action: #selector(openPhraseReplacement(_:)), keyEquivalent: "") + menu.addItem( + withTitle: NSLocalizedString("Edit Associated Phrases…", comment: ""), + action: #selector(openAssociatedPhrases(_:)), keyEquivalent: "") + menu.addItem( + withTitle: NSLocalizedString("Edit User Symbol & Emoji Data…", comment: ""), + action: #selector(openUserSymbols(_:)), keyEquivalent: "") + } + + if optionKeyPressed || !mgrPrefs.shouldAutoReloadUserDataFiles { + menu.addItem( + withTitle: NSLocalizedString("Reload User Phrases", comment: ""), + action: #selector(reloadUserPhrases(_:)), keyEquivalent: "") + } + + menu.addItem(NSMenuItem.separator()) // --------------------- + + menu.addItem( + withTitle: NSLocalizedString("vChewing Preferences…", comment: ""), + action: #selector(showPreferences(_:)), keyEquivalent: "") + if !optionKeyPressed { + menu.addItem( + withTitle: NSLocalizedString("Check for Updates…", comment: ""), + action: #selector(checkForUpdate(_:)), keyEquivalent: "") + } + menu.addItem( + withTitle: NSLocalizedString("Reboot vChewing…", comment: ""), + action: #selector(selfTerminate(_:)), keyEquivalent: "") + menu.addItem( + withTitle: NSLocalizedString("About vChewing…", comment: ""), + action: #selector(showAbout(_:)), keyEquivalent: "") + if optionKeyPressed { + menu.addItem( + withTitle: NSLocalizedString("Uninstall vChewing…", comment: ""), + action: #selector(selfUninstall(_:)), keyEquivalent: "") + } + + // NSMenu 會阻止任何 modified key 相關的訊號傳回輸入法,所以咱們在此重設鍵盤佈局 + setKeyLayout() + + return menu + } + + // MARK: - IME Menu Items + + @objc override func showPreferences(_ sender: Any?) { + (NSApp.delegate as? AppDelegate)?.showPreferences() + NSApp.activate(ignoringOtherApps: true) + } + + @objc func toggleSCPCTypingMode(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("Per-Char Select Mode", comment: ""), "\n", + mgrPrefs.toggleSCPCTypingModeEnabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func toggleChineseConverter(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("Force KangXi Writing", comment: ""), "\n", + mgrPrefs.toggleChineseConversionEnabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func toggleShiftJISShinjitaiOutput(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("JIS Shinjitai Output", comment: ""), "\n", + mgrPrefs.toggleShiftJISShinjitaiOutputEnabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func toggleHalfWidthPunctuation(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("Half-Width Punctuation Mode", comment: ""), + "\n", + mgrPrefs.toggleHalfWidthPunctuationEnabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func toggleCNS11643Enabled(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("CNS11643 Mode", comment: ""), "\n", + mgrPrefs.toggleCNS11643Enabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func toggleSymbolEnabled(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("Symbol & Emoji Input", comment: ""), "\n", + mgrPrefs.toggleSymbolInputEnabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func toggleAssociatedPhrasesEnabled(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("Per-Char Associated Phrases", comment: ""), + "\n", + mgrPrefs.toggleAssociatedPhrasesEnabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func togglePhraseReplacement(_ sender: Any?) { + NotifierController.notify( + message: String( + format: "%@%@%@", NSLocalizedString("Use Phrase Replacement", comment: ""), "\n", + mgrPrefs.togglePhraseReplacementEnabled() + ? NSLocalizedString("NotificationSwitchON", comment: "") + : NSLocalizedString("NotificationSwitchOFF", comment: ""))) + } + + @objc func selfUninstall(_ sender: Any?) { + (NSApp.delegate as? AppDelegate)?.selfUninstall() + } + + @objc func selfTerminate(_ sender: Any?) { + NSApp.terminate(nil) + } + + @objc func checkForUpdate(_ sender: Any?) { + (NSApp.delegate as? AppDelegate)?.checkForUpdate(forced: true) + } + + @objc func openUserPhrases(_ sender: Any?) { + IME.openPhraseFile(userFileAt: mgrLangModel.userPhrasesDataPath(IME.getInputMode())) + } + + @objc func openUserDataFolder(_ sender: Any?) { + if !mgrLangModel.checkIfUserDataFolderExists() { + return + } + NSWorkspace.shared.openFile( + mgrLangModel.dataFolderPath(isDefaultFolder: false), withApplication: "Finder") + } + + @objc func openExcludedPhrases(_ sender: Any?) { + IME.openPhraseFile(userFileAt: mgrLangModel.excludedPhrasesDataPath(IME.getInputMode())) + } + + @objc func openUserSymbols(_ sender: Any?) { + IME.openPhraseFile(userFileAt: mgrLangModel.userSymbolDataPath(IME.getInputMode())) + } + + @objc func openPhraseReplacement(_ sender: Any?) { + IME.openPhraseFile(userFileAt: mgrLangModel.phraseReplacementDataPath(IME.getInputMode())) + } + + @objc func openAssociatedPhrases(_ sender: Any?) { + IME.openPhraseFile(userFileAt: mgrLangModel.userAssociatedPhrasesDataPath(IME.getInputMode())) + } + + @objc func reloadUserPhrases(_ sender: Any?) { + mgrLangModel.loadUserPhrases() + mgrLangModel.loadUserPhraseReplacement() + } + + @objc func showAbout(_ sender: Any?) { + (NSApp.delegate as? AppDelegate)?.showAbout() + NSApp.activate(ignoringOtherApps: true) + } +} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index cc2cfdac..7524cb15 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 5B73FB5E27B2BE1300E9BF49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5B73FB6027B2BE1300E9BF49 /* InfoPlist.strings */; }; 5B7BC4B027AFFBE800F66C24 /* frmPrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5B7BC4AE27AFFBE800F66C24 /* frmPrefWindow.xib */; }; 5BAD0CD527D701F6003D127F /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; }; + 5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */; }; 5BBBB75F27AED54C0023B93A /* Beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75D27AED54C0023B93A /* Beep.m4a */; }; 5BBBB76027AED54C0023B93A /* Fart.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB75E27AED54C0023B93A /* Fart.m4a */; }; 5BBBB76B27AED5DB0023B93A /* frmNonModalAlertWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BBBB76527AED5DB0023B93A /* frmNonModalAlertWindow.xib */; }; @@ -187,6 +188,7 @@ 5B7BC4AF27AFFBE800F66C24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Source/WindowNIBs/Base.lproj/frmPrefWindow.xib; sourceTree = ""; }; 5B7BC4B227AFFC0B00F66C24 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Source/WindowNIBs/en.lproj/frmPrefWindow.strings; sourceTree = ""; }; 5B8F43ED27C9BC220069AC27 /* SymbolLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SymbolLM.h; sourceTree = ""; }; + 5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlInputMethod_Menu.swift; sourceTree = ""; }; 5BBBB75D27AED54C0023B93A /* Beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Beep.m4a; sourceTree = ""; }; 5BBBB75E27AED54C0023B93A /* Fart.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Fart.m4a; sourceTree = ""; }; 5BBBB76627AED5DB0023B93A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmNonModalAlertWindow.xib; sourceTree = ""; }; @@ -409,6 +411,7 @@ isa = PBXGroup; children = ( D4A13D5927A59D5C003BE359 /* ctlInputMethod.swift */, + 5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */, 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */, 5B62A33527AE795800A19448 /* mgrPrefs.swift */, ); @@ -990,6 +993,7 @@ 5BF8423127BAA942008E7E4C /* vChewingKanjiConverter.swift in Sources */, 5B62A34627AE7CD900A19448 /* ctlCandidateHorizontal.swift in Sources */, 5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */, + 5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */, D41355DE278EA3ED005E5CBD /* UserPhrasesLM.mm in Sources */, 6ACC3D3F27914F2400F1B140 /* KeyValueBlobReader.cpp in Sources */, D41355D8278D74B5005E5CBD /* mgrLangModel.mm in Sources */,