// // KMLanguageViewController.swift // PDF Reader Pro // // Created by liujiajie on 2023/11/16. // import Cocoa @objc(KMLanguageTableCellViewDelegate) protocol KMLanguageTableCellViewDelegate: AnyObject { @objc optional func tableCellViewCheckButtonDidChange(_ cell: KMLanguageTableCellView) } class KMLanguageTableCellView: NSTableCellView{ var delegate: KMLanguageTableCellViewDelegate? var language: [String: String] = [:] @IBOutlet var checkButton: NSButton! @IBAction func checkButtonAction(_ sender: NSButton) { self.delegate?.tableCellViewCheckButtonDidChange?(self) } } class KMLanguageViewController: NSViewController,KMLanguageTableCellViewDelegate,NSOutlineViewDelegate,NSOutlineViewDataSource,NSTokenFieldDelegate{ @IBOutlet var tokenField: NSTokenField! @IBOutlet var outlineView: NSOutlineView! var languages: NSArray? lazy var selectedLanguages: NSMutableArray = { if KMGOCRManager.default().selectedLanguages == nil { KMGOCRManager.default().selectedLanguages = NSMutableArray() } return KMGOCRManager.default().selectedLanguages! }() var builtInKeywords: Array? override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } required init?(coder: NSCoder) { super.init(coder: coder) } override func awakeFromNib() { super.awakeFromNib() self.languages = KMGOCRManager.languages() as NSArray self.outlineView.reloadData() self.builtInKeywords = self.languages?.value(forKeyPath: KMGOCRLanguageStringKey) as? [String] self.tokenField.cell?.lineBreakMode = .byTruncatingTail self.updateTokenField() } func updateTokenField() { self.tokenField.objectValue = self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey) // commit the edit change let fieldEditor = self.tokenField.currentEditor() fieldEditor?.selectedRange = NSRange(location: fieldEditor?.string.count ?? 0, length: 0) } func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { return self.languages?.count ?? 0 } func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { return self.languages?[index] as Any } func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { return false } func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { if let itemDictionary = item as? NSDictionary { let result = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "DataCell"), owner: self) as? KMLanguageTableCellView result?.textField?.stringValue = itemDictionary[KMGOCRLanguageStringKey] as? String ?? "" result?.checkButton.state = self.selectedLanguages.contains(itemDictionary) ? .on : .off result?.language = itemDictionary as! [String : String] result?.delegate = self return result } return nil } func outlineView(_ outlineView: NSOutlineView, shouldSelectItem item: Any) -> Bool { return false } func tableCellViewCheckButtonDidChange(_ cell: KMLanguageTableCellView) { if cell.checkButton.state == .on { if !self.selectedLanguages.contains(cell.language) { self.selectedLanguages.add(cell.language) } } else { if self.selectedLanguages.contains(cell.language) { self.selectedLanguages.remove(cell.language) } } self.updateTokenField() NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMOCRSelectedLanguagesChangeNotification"), object: self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey)) } //MARK: NSTokenFieldDelegate func tokenField(_ tokenField: NSTokenField, shouldAdd tokens: [Any], at index: Int) -> [Any] { let newTokens = NSMutableArray() for string in tokens { let arr: NSArray = self.builtInKeywords! as NSArray if arr.contains(string) { newTokens.add(string as! String) } else { continue } let ar: NSArray = self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey) as! NSArray if !ar.contains(string) { let index = (self.languages?.value(forKeyPath: KMGOCRLanguageStringKey) as AnyObject).index(of: string) if let OCRLanguage = self.languages?[index] as? NSDictionary { self.selectedLanguages.add(OCRLanguage) } } } self.outlineView.reloadData() NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMOCRSelectedLanguagesChangeNotification"), object: self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey)) return newTokens as! [String] } func tokenField(_ tokenField: NSTokenField, completionsForSubstring substring: String, indexOfToken tokenIndex: Int, indexOfSelectedItem selectedIndex: UnsafeMutablePointer?) -> [Any]? { let arrayFilter = self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey) as? NSArray // let str = String(format: "NOT (SELF in %@)", arrayFilter ?? "{}") let thePredicate = NSPredicate(format: "NOT (SELF in %@)", arrayFilter ?? []) let arr: NSArray = self.builtInKeywords! as NSArray let newBuiltInKeywords: NSArray = arr.filtered(using: thePredicate) as NSArray // let str1 = String(format: "SELF beginswith[cd] %@", substring) let matches = newBuiltInKeywords.filtered(using: NSPredicate(format: "SELF beginswith[cd] %@", substring)) return matches } func controlTextDidEndEditing(_ obj: Notification) { let array: NSArray = self.tokenField.objectValue as! NSArray let string = array.lastObject let newArray = NSMutableArray.init(array: array) let arr: NSArray = self.builtInKeywords! as NSArray if !arr.contains(string ?? "") { newArray.remove(string ?? "") } self.tokenField.objectValue = newArray self.selectedLanguages.removeAllObjects() for string in self.tokenField.objectValue as? [String] ?? [] { if !(self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey) as? [String] ?? []).contains(string) { let index = (self.languages?.value(forKeyPath: KMGOCRLanguageStringKey) as AnyObject).index(of: string) if let OCRLanguage = self.languages?[index] as? NSDictionary { self.selectedLanguages.add(OCRLanguage) } } } self.outlineView.reloadData() NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMOCRSelectedLanguagesChangeNotification"), object: self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey)) } func controlTextDidChange(_ obj: Notification) { if selectedLanguages.count > (self.tokenField.objectValue as? [Any] ?? []).count { self.selectedLanguages.removeAllObjects() for string in self.tokenField.objectValue as? [String] ?? [] { if !(self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey) as? [String] ?? []).contains(string) { let index = (self.languages?.value(forKeyPath: KMGOCRLanguageStringKey) as AnyObject).index(of: string) if let OCRLanguage = self.languages?[index] as? NSDictionary { self.selectedLanguages.add(OCRLanguage) } } } self.outlineView.reloadData() NotificationCenter.default.post(name: NSNotification.Name(rawValue: "KMOCRSelectedLanguagesChangeNotification"), object: self.selectedLanguages.value(forKeyPath: KMGOCRLanguageStringKey)) } } }