KMSearchReplaceWindowController.swift 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. //
  2. // KMSearchReplaceWindowController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by User-Tangchao on 2024/8/7.
  6. //
  7. import Cocoa
  8. class KMSearchReplaceWindowController_Window: NSWindow {
  9. override var canBecomeMain: Bool {
  10. return true
  11. }
  12. override var canBecomeKey: Bool {
  13. return true
  14. }
  15. }
  16. @objc enum KMSearchReplaceType: Int {
  17. case none = 0
  18. case search = 1
  19. case replace = 2
  20. }
  21. class KMSearchReplaceWindowController: NSWindowController {
  22. @IBOutlet weak var titleBarBox: NSBox!
  23. @IBOutlet weak var closeButton: NSButton!
  24. @IBOutlet weak var tabBox: NSBox!
  25. @IBOutlet weak var searchTabButton: NSButton!
  26. @IBOutlet weak var replaceTabButton: NSButton!
  27. @IBOutlet weak var tabBottomLine: NSBox!
  28. @IBOutlet weak var tabSelectedLine: NSBox!
  29. @IBOutlet weak var tabSelectedLineLeftConst: NSLayoutConstraint!
  30. @IBOutlet weak var searchBox: NSBox!
  31. @IBOutlet weak var searchTitleLabel: NSTextField!
  32. @IBOutlet weak var searchInputBox: NSBox!
  33. @IBOutlet weak var searchInputView: NSTextField!
  34. @IBOutlet weak var matchWholeCheck: NSButton!
  35. @IBOutlet weak var caseSensitiveCheck: NSButton!
  36. @IBOutlet weak var previousButton: NSButton!
  37. @IBOutlet weak var nextButton: NSButton!
  38. @IBOutlet weak var replaceBox: NSBox!
  39. @IBOutlet weak var bottomBarBox: NSBox!
  40. @IBOutlet weak var replaceButton: NSButton!
  41. @IBOutlet weak var replaceAllButton: NSButton!
  42. private var _modalSession: NSApplication.ModalSession?
  43. private var handdler: KMSearchReplaceHanddler = KMSearchReplaceHanddler()
  44. private var type_: KMSearchReplaceType = .search
  45. deinit {
  46. KMPrint("KMSearchReplaceWindowController deinit.")
  47. }
  48. convenience init(with pdfView: CPDFView?, type: KMSearchReplaceType) {
  49. self.init(windowNibName: "KMSearchReplaceWindowController")
  50. self.handdler.pdfView = pdfView
  51. self.type_ = type
  52. }
  53. override func windowDidLoad() {
  54. super.windowDidLoad()
  55. self.initDefaultValue()
  56. self.switchType(self.type_)
  57. }
  58. func initDefaultValue() {
  59. self.window?.isMovableByWindowBackground = true
  60. self.titleBarBox.boxType = .custom
  61. self.titleBarBox.borderWidth = 0
  62. self.closeButton.imagePosition = .imageOnly
  63. self.closeButton.image = NSImage(named: "KMImageNameUXIconBtnCloseNor")
  64. self.closeButton.target = self
  65. self.closeButton.action = #selector(_closeAction)
  66. self.searchTabButton.target = self
  67. self.searchTabButton.action = #selector(_searchTabAction)
  68. self.searchTabButton.title = " \(NSLocalizedString("Search", comment: ""))"
  69. self.searchTabButton.image = NSImage(named: "KMImageNameSearchIcon")
  70. self.searchTabButton.imagePosition = .imageLeft
  71. // self.searchTabButton.imageHugsTitle = true
  72. self.replaceTabButton.target = self
  73. self.replaceTabButton.action = #selector(_replaceTabAction)
  74. self.replaceTabButton.title = " \(NSLocalizedString("Replace", comment: ""))"
  75. self.replaceTabButton.image = NSImage(named: "KMImageNameReplaceIcon")
  76. self.replaceTabButton.imagePosition = .imageLeft
  77. self.tabSelectedLine.borderWidth = 0
  78. self.tabSelectedLine.fillColor = NSColor(hex: "#4982E6")
  79. self.searchBox.borderWidth = 0
  80. self.searchTitleLabel.stringValue = NSLocalizedString("Search", comment: "")
  81. self.searchInputBox.cornerRadius = 0
  82. self.searchInputView.drawsBackground = false
  83. self.searchInputView.isBordered = false
  84. self.searchInputView.delegate = self
  85. self.matchWholeCheck.title = NSLocalizedString("Whole Words Only", comment: "")
  86. self.caseSensitiveCheck.title = NSLocalizedString("Ignore Case", comment: "")
  87. self.previousButton.title = NSLocalizedString("Previous", comment: "")
  88. self.previousButton.target = self
  89. self.previousButton.action = #selector(_previousAction)
  90. self.nextButton.title = NSLocalizedString("Next", comment: "")
  91. self.nextButton.target = self
  92. self.nextButton.action = #selector(_nextAction)
  93. self.replaceButton.title = NSLocalizedString("Replace", comment: "")
  94. self.replaceAllButton.title = NSLocalizedString("Replace All", comment: "")
  95. }
  96. // MARK: - Actions
  97. @objc private func _closeAction(_ sender: NSButton) {
  98. self.endModal(sender)
  99. }
  100. @objc private func _previousAction(_ sender: NSButton) {
  101. guard let model = self.handdler.searchResults.safe_element(for: self.handdler.showIdx+1) as? KMSearchMode else {
  102. return
  103. }
  104. self.handdler.showIdx += 1
  105. self.handdler.showSelection(model.selection)
  106. }
  107. @objc private func _nextAction(_ sender: NSButton) {
  108. guard let model = self.handdler.searchResults.safe_element(for: self.handdler.showIdx-1) as? KMSearchMode else {
  109. return
  110. }
  111. self.handdler.showIdx -= 1
  112. self.handdler.showSelection(model.selection)
  113. }
  114. @objc private func _searchTabAction(_ sender: NSButton) {
  115. self.switchType(.search, animate: true)
  116. }
  117. @objc private func _replaceTabAction(_ sender: NSButton) {
  118. self.switchType(.replace, animate: true)
  119. }
  120. func switchType(_ type: KMSearchReplaceType, animate: Bool = false) {
  121. if type == .replace {
  122. if IAPProductsManager.default().isAvailableAllFunction() == false {
  123. KMPurchaseCompareWindowController.sharedInstance().showWindow(nil)
  124. return
  125. }
  126. }
  127. self.type_ = type
  128. let selectedColor = NSColor(hex: "0E1114")
  129. let unSelectedColor = NSColor(hex: "757780")
  130. if type == .search { // 248
  131. self.tabSelectedLineLeftConst.constant = 24
  132. self.searchTabButton.setTitleColor(selectedColor)
  133. self.searchTabButton.image = NSImage(named: "KMImageNameSearchIcon")
  134. self.replaceTabButton.setTitleColor(unSelectedColor)
  135. self.replaceTabButton.image = NSImage(named: "KMImageNameReplaceUnselectedIcon")
  136. // DispatchQueue.main.async {
  137. self.replaceBox.isHidden = true
  138. self.bottomBarBox.isHidden = true
  139. // }
  140. var frame = self.window?.frame ?? .zero
  141. let height: CGFloat = 248+20
  142. let heightOffset = frame.size.height - height
  143. frame.origin.y += heightOffset
  144. frame.size.height = height
  145. self.window?.setFrame(frame, display: true, animate: animate)
  146. self.window?.minSize = frame.size
  147. self.window?.maxSize = frame.size
  148. } else if type == .replace { // 388
  149. self.tabSelectedLineLeftConst.constant = 140
  150. self.searchTabButton.setTitleColor(unSelectedColor)
  151. self.searchTabButton.image = NSImage(named: "KMImageNameSearchUnselectedIcon")
  152. self.replaceTabButton.setTitleColor(selectedColor)
  153. self.replaceTabButton.image = NSImage(named: "KMImageNameReplaceIcon")
  154. DispatchQueue.main.async {
  155. self.replaceBox.isHidden = false
  156. self.bottomBarBox.isHidden = false
  157. }
  158. var frame = self.window?.frame ?? .zero
  159. let height:CGFloat = 388
  160. let heightOffset = frame.size.height-height
  161. frame.origin.y += heightOffset
  162. frame.size.height = height
  163. self.window?.setFrame(frame, display: true, animate: animate)
  164. self.window?.minSize = frame.size
  165. self.window?.maxSize = frame.size
  166. }
  167. }
  168. func startModal(_ sender: AnyObject?) {
  169. NSApp.stopModal()
  170. var modalCode: NSApplication.ModalResponse?
  171. if let _win = self.window {
  172. self._modalSession = NSApp.beginModalSession(for: _win)
  173. repeat {
  174. modalCode = NSApp.runModalSession(self._modalSession!)
  175. } while (modalCode == .continue)
  176. }
  177. }
  178. func endModal(_ sender: AnyObject?) {
  179. if let session = self._modalSession {
  180. NSApp.stopModal()
  181. NSApp.endModalSession(session)
  182. self.window?.orderOut(self)
  183. }
  184. if let winC = self.window?.kmCurrentWindowC, winC.isEqual(to: self) {
  185. self.window?.kmCurrentWindowC = nil
  186. }
  187. }
  188. }
  189. extension KMSearchReplaceWindowController: NSTextFieldDelegate {
  190. func controlTextDidEndEditing(_ obj: Notification) {
  191. }
  192. func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
  193. switch commandSelector {
  194. case #selector(NSResponder.insertNewline(_:)):
  195. if let inputView = control as? NSTextField {
  196. // //当当前TextField按下enter
  197. if inputView == self.searchInputView {
  198. let isCase = self.caseSensitiveCheck.state == .on
  199. let isWholeWord = self.matchWholeCheck.state == .on
  200. self.handdler.search(keyword: self.searchInputView.stringValue, isCase: isCase, isWholeWord: isWholeWord, callback: { [weak self] datas in
  201. if let sel = datas?.first?.selection {
  202. self?.handdler.showIdx = 0
  203. self?.handdler.showSelection(sel)
  204. }
  205. })
  206. }
  207. }
  208. return true
  209. default:
  210. return false
  211. }
  212. }
  213. }