// // KMSearchFindView.swift // PDF Reader Pro // // Created by lizhe on 2024/1/17. // import Cocoa typealias KMSearchFindViewDoneAction = (_ view: KMSearchFindView) -> Void typealias KMSearchFindViewSearchAction = (_ view: KMSearchFindView, _ searchString: String, _ forward: Bool) -> Bool typealias KMSearchFindViewShowAllAction = (_ view: KMSearchFindView, _ searchString: String, _ forward: Bool) -> Void class KMSearchFindView: KMBaseXibView { @IBOutlet var findField: NSSearchField! @IBOutlet var messageField: NSTextField! @IBOutlet var doneButton: NSButton! @IBOutlet var navigationButton: NSSegmentedControl! @IBOutlet var showAllButton: NSButton! var ownerController: AnyObject? var findString: String? private var lastChangeCount: Int = 0 private var didChange: Bool = false private var animating: Bool = false var showAllAction: KMSearchFindViewShowAllAction? var doneAction: KMSearchFindViewDoneAction? var searchAction: KMSearchFindViewSearchAction? override func setup() { findField.delegate = self refreshSearchBarMenu() self.showAllButton.title = NSLocalizedString("Show All", comment: "") self.doneButton.title = NSLocalizedString("Done", comment: "") } private func refreshSearchBarMenu() { var words = UserDefaults.standard.object(forKey: "kmDocumentSearchWordArrays") as? [String] if words == nil { UserDefaults.standard.setValue([], forKey: "kmDocumentSearchWordArrays") words = [] } guard let words = words else { return } let searchMenu = NSMenu() for word in words { var tword = word if word.count > 15 { tword = String(word.prefix(15)) + "..." } let item = searchMenu.addItem(withTitle: tword, action: #selector(searchPDFKeyWord(_:)), keyEquivalent: "") item.representedObject = tword } let attrited = [NSAttributedString.Key.font: NSFont(name: "Helvetica", size: 12.0)!] if words.count > 0 { let attributedString = NSAttributedString(string: NSLocalizedString("Search History", comment: ""), attributes: attrited) let item = NSMenuItem() item.attributedTitle = attributedString searchMenu.insertItem(item, at: 0) searchMenu.addItem(NSMenuItem.separator()) let attributedString1 = NSAttributedString(string: NSLocalizedString("Clear Search History", comment: ""), attributes: attrited) let item1 = NSMenuItem() item1.attributedTitle = attributedString1 item1.action = #selector(clearSearchWordHistory(_:)) item1.target = self searchMenu.addItem(item1) searchMenu.insertItem(NSMenuItem.separator(), at: 0) } let attributedString2 = NSAttributedString(string: NSLocalizedString("Ignore Case", comment: ""), attributes: attrited) let ignoreItem = NSMenuItem() ignoreItem.attributedTitle = attributedString2 ignoreItem.action = #selector(toggleCaseInsensitiveFind(_:)) ignoreItem.target = self searchMenu.insertItem(ignoreItem, at: 0) (findField.cell! as! NSSearchFieldCell).searchMenuTemplate = searchMenu } private func windowDidBecomeKey() { let findPboard = NSPasteboard(name: NSPasteboard.Name.find) if lastChangeCount < findPboard.changeCount { if let strings = findPboard.readObjects(forClasses: [NSString.self], options: [:]) as? [String], let firstString = strings.first { setFindString(firstString) lastChangeCount = findPboard.changeCount didChange = false } } } private func windowDidResignKey() { updateFindPboard() } private func updateFindPboard() { if didChange { let findPboard = NSPasteboard(name: NSPasteboard.Name.find) findPboard.clearContents() findPboard.writeObjects([findString! as NSPasteboardWriting]) lastChangeCount = findPboard.changeCount didChange = false } } func setFindString(_ newFindString: String?) { if findString != newFindString { findString = newFindString didChange = true } } func findForward(_ forward: Bool) { var found = true if let findStringLength = findString?.count, findStringLength > 0 { guard let searchAction = searchAction else { return } found = searchAction(self,findString!,forward) updateFindPboard() if var words = UserDefaults.standard.object(forKey: "kmDocumentSearchWordArrays") as? [String] { if let index = words.firstIndex(of: findString!) { words.remove(at: index) } words.insert(findString!, at: 0) if words.count > 10 { words.removeLast() } UserDefaults.standard.set(words, forKey: "kmDocumentSearchWordArrays") UserDefaults.standard.synchronize() refreshSearchBarMenu() } } messageField.isHidden = found } @IBAction func find(_ sender: Any) { findForward((sender as AnyObject).selectedTag() == 1) } @IBAction func buttonItemClick_ShowAll(_ sender: NSButton) { self.findString = findField.stringValue showAllAction?(self, self.findString ?? "", findField.selectedTag() == 1) } @IBAction func remove(_ sender: Any) { doneAction?(self) } @IBAction func toggleCaseInsensitiveFind(_ sender: Any) { // let caseInsensitive = UserDefaults.standard.bool(forKey: SKCaseInsensitiveFindKey) // UserDefaults.standard.set(!caseInsensitive, forKey: SKCaseInsensitiveFindKey) let caseInsensitive = UserDefaults.standard.bool(forKey: SKCaseInsensitiveFindKey) UserDefaults.standard.set(!caseInsensitive, forKey: SKCaseInsensitiveFindKey) } @objc func clearSearchWordHistory(_ sender: Any) { UserDefaults.standard.removeObject(forKey: "kmDocumentSearchWordArrays") UserDefaults.standard.synchronize() refreshSearchBarMenu() } @objc func searchPDFKeyWord(_ item: NSMenuItem) { let word = item.representedObject as? String ?? "" findField.stringValue = word findString = word findForward(true) } @objc func searchString(_ string: String) { let word = string findField.stringValue = word findString = word findForward(true) } // override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { // if menuItem.action == #selector(toggleCaseInsensitiveFind(_:)) { // menuItem.state = UserDefaults.standard.bool(forKey: SKCaseInsensitiveFindKey) ? .on : .off // return true // } // return true // } func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool { if commandSelector == #selector(cancelOperation(_:)) { doneButton.performClick(nil) return true } return false } } extension KMSearchFindView: NSSearchFieldDelegate { func searchFieldDidEndSearching(_ sender: NSSearchField) { print("searchFieldDidEndSearching") } func controlTextDidEndEditing(_ obj: Notification) { let fied: NSTextField = obj.object as! NSTextField; if fied.isEqual(self.findField) { print("controlTextDidEndEditing") findString = self.findField.stringValue self.find(self.findField as Any) } } }