KMSearchViewController.swift 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. //
  2. // KMSearchViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by lxy on 2022/11/17.
  6. //
  7. import Cocoa
  8. @objc protocol KMSearchViewControllerDelegate {
  9. @objc optional func searchDoneAction(viewController:KMSearchViewController)
  10. @objc optional func searchAction(searchString:String, isCase:Bool)
  11. }
  12. class CSearchFieldCustomCell : NSSearchFieldCell {
  13. required init(coder: NSCoder) {
  14. super.init(coder: coder)
  15. let cancelCell = self.cancelButtonCell
  16. let cancelImage = NSImage(named: "KMImageNameTriBtnClear")
  17. cancelImage?.size = NSMakeSize(16, 16)
  18. cancelCell?.image = cancelImage
  19. cancelCell?.alternateImage = cancelImage
  20. let searchCell = self.searchButtonCell
  21. let searchImage = NSImage(named: "KMImageNameSearchLeftImage")
  22. searchImage?.size = NSMakeSize(16, 16)
  23. searchCell?.image = searchImage
  24. searchCell?.alternateImage = searchImage
  25. }
  26. override func resetCancelButtonCell() {
  27. super.resetCancelButtonCell()
  28. }
  29. }
  30. class KMSearchViewController: NSViewController {
  31. let CPDFOfficeSearchHistoryKey = "CPDFOfficeSearchHistoryKey"
  32. @IBOutlet weak var findTipTextField: NSTextField!
  33. @IBOutlet weak var resultTextField: NSTextField!
  34. @IBOutlet weak var allTipTextField: NSTextField!
  35. @IBOutlet weak var lineView: NSView!
  36. @IBOutlet weak var searchCotentView: NSView!
  37. @IBOutlet weak var searchTextField: FocusAwareSearchTextField!
  38. @IBOutlet weak var doneButton: NSButton!
  39. @IBOutlet weak var outlineView: KMOutlineView!
  40. var isCase = false
  41. let searchFieldMenu = NSMenu()
  42. @IBOutlet weak var emptyView: NSView!
  43. @IBOutlet weak var tipTitleLabel: NSTextField!
  44. @IBOutlet weak var searResultLabel: NSTextField!
  45. //select 多选
  46. var selectItems: [KMSearchMode] = []
  47. var listView : CPDFListView!
  48. var searchResults : [KMSearchMode] = []
  49. var sortResults : [KMSearchMode] = []
  50. var isCancelCell : String = ""
  51. var previousSearchString: String = ""
  52. var previousCase: Bool = true
  53. open weak var delegate: KMSearchViewControllerDelegate?
  54. override func viewDidLoad() {
  55. super.viewDidLoad()
  56. // Do view setup here.
  57. self.setup()
  58. }
  59. override func viewDidAppear() {
  60. super.viewDidAppear()
  61. NSApplication.shared.mainWindow?.makeFirstResponder(self.searchTextField)
  62. }
  63. override func viewWillDisappear() {
  64. super.viewWillDisappear()
  65. self.cancelAllSearchModel()
  66. }
  67. override func viewWillAppear() {
  68. super.viewWillAppear()
  69. // self.selectAllSearchModel()
  70. self.searchDoneAction()
  71. }
  72. func setup() {
  73. self.view.backgroundColor(NSColor.km_init(hex: "#F7F8FA"))
  74. //空状态
  75. self.emptyView.isHidden = true
  76. self.searResultLabel.stringValue = NSLocalizedString("No Search Results", comment: "")
  77. self.searResultLabel.font = NSFont.SFProTextRegularFont(14.0)
  78. self.searResultLabel.textColor = NSColor.km_init(hex: "#616469")
  79. self.tipTitleLabel.font = NSFont.SFProTextRegularFont(12.0)
  80. self.tipTitleLabel.textColor = NSColor.km_init(hex: "#94989C")
  81. let paragraphStyle = NSMutableParagraphStyle()
  82. paragraphStyle.lineHeightMultiple = 1.32
  83. paragraphStyle.alignment = .center
  84. self.tipTitleLabel.attributedStringValue = NSMutableAttributedString(string: NSLocalizedString("Search text can be entered above", comment: ""), attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle])
  85. self.lineView.backgroundColor(NSColor.km_init(hex: "#EDEEF0"))
  86. //搜索
  87. self.searchCotentView.backgroundColor(NSColor.km_init(hex: "#FFFFFF"))
  88. self.searchCotentView.border()
  89. self.searchTextField.delegate = self
  90. self.searchTextField.border(NSColor.km_init(hex: "#FFFFFF"), 1, 0)
  91. self.searchTextField.textColor = NSColor.km_init(hex: "#252629")
  92. self.searchTextField.font = NSFont.SFProTextRegularFont(14.0)
  93. let search = UserDefaults.standard.object(forKey: "CPDFOfficeSearchIgnoreCaseKey")
  94. if search == nil {
  95. self.isCase = true
  96. } else {
  97. self.isCase = UserDefaults.standard.bool(forKey: "CPDFOfficeSearchIgnoreCaseKey")
  98. }
  99. self.previousCase = self.isCase
  100. self.findTipTextField.stringValue = NSLocalizedString("Search", comment: "")
  101. self.findTipTextField.font = NSFont.SFProTextSemiboldFont(14.0)
  102. self.findTipTextField.textColor = NSColor.km_init(hex: "#252629")
  103. self.doneButton.isHidden = true
  104. self.doneButton.title = NSLocalizedString("Done", comment: "")
  105. self.doneButton.backgroundColor(NSColor.km_init(hex: "#1770F4"))
  106. self.doneButton.font = NSFont.SFProTextRegularFont(12.0)
  107. self.doneButton.contentTintColor = NSColor.km_init(hex: "#FFFFFF")
  108. self.doneButton.border(NSColor.km_init(hex: "#1770F4"), 0, 4)
  109. //显示
  110. self.allTipTextField.stringValue = NSLocalizedString("All", comment: "")
  111. self.allTipTextField.font = NSFont.SFProTextSemiboldFont(11.0)
  112. self.allTipTextField.textColor = NSColor.km_init(hex: "#252629")
  113. self.resultTextField.stringValue = NSLocalizedString("Results", comment: "") + ":"
  114. self.resultTextField.font = NSFont.SFProTextSemiboldFont(11.0)
  115. self.resultTextField.textColor = NSColor.km_init(hex: "#94989C")
  116. self.outlineView.allowsMultipleSelection = true
  117. self.outlineView.indentationPerLevel = 0
  118. self.updateSearchMenu()
  119. (self.searchTextField.cell! as! NSSearchFieldCell).placeholderString = NSLocalizedString("Search PDF", comment: "")
  120. self.reloadData()
  121. }
  122. private func updateSearchMenu() {
  123. searchFieldMenu.removeAllItems()
  124. let item = searchFieldMenu.addItem(withTitle: NSLocalizedString("Ignore Case", comment: ""), action: #selector(caseSetAction), target: self)
  125. if self.isCase {
  126. item?.state = .on
  127. } else {
  128. item?.state = .off
  129. }
  130. let searchs : [String] = UserDefaults.standard.object(forKey: CPDFOfficeSearchHistoryKey) as? [String] ?? []
  131. if searchs.count > 0 {
  132. searchFieldMenu.addItem(NSMenuItem.separator())
  133. searchFieldMenu.addItem(withTitle: NSLocalizedString("Search History", comment: ""), action: nil, target: self)
  134. for search in searchs {
  135. searchFieldMenu.addItem(withTitle: search, action: #selector(searchHistoryAction), target: self)
  136. }
  137. searchFieldMenu.addItem(NSMenuItem.separator())
  138. searchFieldMenu.addItem(withTitle: NSLocalizedString("Clear Search History", comment: ""), action: #selector(clearSearchHistoryAction), target: self)
  139. self.searchFieldMenu.font = NSFont.SFProTextRegularFont(13.0)
  140. }
  141. (self.searchTextField.cell! as! NSSearchFieldCell).searchMenuTemplate = searchFieldMenu
  142. // let menus : NSMenu = NSMenu(title: "")
  143. // menus.addItem(withTitle: NSLocalizedString("Add Crice", comment: ""), action: #selector(addAnonationStyle), target: self, tag: CAnnotationType.circle.rawValue)
  144. // menus.addItem(withTitle: NSLocalizedString("Add Square", comment: ""), action: #selector(addAnonationStyle), target: self, tag: CAnnotationType.square.rawValue)
  145. // menus.addItem(withTitle: NSLocalizedString("Add Highlight", comment: ""), action: #selector(addAnonationStyle), target: self, tag: CAnnotationType.highlight.rawValue)
  146. // menus.addItem(withTitle: NSLocalizedString("Add Underline", comment: ""), action: #selector(addAnonationStyle), target: self, tag: CAnnotationType.underline.rawValue)
  147. // menus.addItem(withTitle: NSLocalizedString("Add Strikeththrough", comment: ""), action: #selector(addAnonationStyle), target: self, tag: CAnnotationType.strikeOut.rawValue)
  148. // self.outlineView.menu = menus
  149. }
  150. func selectedRowIndexs() -> IndexSet {
  151. let clickRow = self.outlineView.clickedRow
  152. var selectedRowIndexs = self.outlineView.selectedRowIndexes
  153. if(clickRow != -1 && !selectedRowIndexs.contains(clickRow)) {
  154. selectedRowIndexs = [clickRow]
  155. }
  156. return selectedRowIndexs
  157. }
  158. public func reloadData() {
  159. self.sortResults = KMSearchMode.sortSearchResult(results: self.searchResults)
  160. if self.searchResults.count > 1 {
  161. self.resultTextField.stringValue = "Results:\(self.searchResults.count)"
  162. } else {
  163. self.resultTextField.stringValue = "Result:\(self.searchResults.count)"
  164. }
  165. self.listView.setHighlightedSelection(nil, animated: true)
  166. self.outlineView.reloadData()
  167. }
  168. }
  169. //MARK: Search
  170. extension KMSearchViewController: NSSearchFieldDelegate {
  171. private func searchDoneAction() {
  172. var searchs : [String] = UserDefaults.standard.object(forKey: CPDFOfficeSearchHistoryKey) as? [String] ?? []
  173. let searchString = self.searchTextField.stringValue
  174. if searchString != "" && (self.previousSearchString != searchString || self.isCase != self.previousCase) {
  175. //缓存搜索词汇是否重复
  176. if searchs.contains(searchString) {
  177. searchs.removeObject(searchString)
  178. }
  179. if searchs.count == 10 {
  180. searchs.remove(at: 9)
  181. }
  182. searchs.insert((self.searchTextField.stringValue), at: 0)
  183. UserDefaults.standard.set(searchs, forKey: CPDFOfficeSearchHistoryKey)
  184. self.updateSearchMenu()
  185. self.delegate?.searchAction?(searchString: self.searchTextField.stringValue,isCase:self.isCase)
  186. self.doneButton.isHidden = false
  187. for model in self.sortResults {
  188. model.select = true
  189. }
  190. self.outlineView.expandItem(nil, expandChildren: true)
  191. self.selectAllSearchModel()
  192. self.previousSearchString = searchString
  193. self.previousCase = self.isCase
  194. }
  195. //移除响应
  196. NSApplication.shared.mainWindow?.makeFirstResponder(self)
  197. }
  198. func selectAllSearchModel() {
  199. //需要延时2s 不然不会高亮
  200. // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { [unowned self] in
  201. //高亮所有注释
  202. var selections: [CPDFSelection] = []
  203. for model in self.sortResults {
  204. for item in model.datas {
  205. item.selection.setColor(NSColor.km_init(hex: "#FFE600").withAlphaComponent(0.5))
  206. selections.append(item.selection)
  207. }
  208. }
  209. self.listView.setHighlightedSelections(selections)
  210. self.listView.setNeedsDisplayAnnotationViewForVisiblePages()
  211. // }
  212. }
  213. func cancelAllSearchModel() {
  214. self.listView.setHighlightedSelections(nil)
  215. self.listView.setHighlightedSelection(nil, animated: true)
  216. self.listView.setNeedsDisplayAnnotationViewForVisiblePages()
  217. self.outlineView.deselectAll(nil)
  218. //清空搜索词汇
  219. self.previousSearchString = ""
  220. }
  221. }
  222. //MARK: Action
  223. extension KMSearchViewController {
  224. @IBAction func addAnonationStyle(sender: NSMenuItem) {
  225. let selectRowIndexs = self.selectedRowIndexs()
  226. if selectRowIndexs.count > 0 {
  227. var newAnnonations : [CPDFAnnotation] = []
  228. for selectRow in selectRowIndexs {
  229. let searchModel = self.outlineView.item(atRow: selectRow) as! KMSearchMode
  230. if searchModel.datas.count > 0 { //选了到了1页
  231. for search in searchModel.datas {
  232. let selection = search.selection
  233. let annotation = self.listView.addAnnotation(with: CAnnotationType(rawValue: sender.tag) ?? CAnnotationType.unkown, selection: selection, page: selection.page, bounds: selection.bounds)
  234. self.listView.setNeedsDisplayAnnotationViewFor(selection.page)
  235. if annotation != nil {
  236. newAnnonations.append(annotation!)
  237. }
  238. }
  239. } else { //选到页码里的条数
  240. let selection = searchModel.selection
  241. let annotation = self.listView.addAnnotation(with: CAnnotationType(rawValue: sender.tag) ?? CAnnotationType.unkown, selection: selection, page: selection.page, bounds: selection.bounds)
  242. self.listView.setNeedsDisplayAnnotationViewFor(selection.page)
  243. if annotation != nil {
  244. newAnnonations.append(annotation!)
  245. }
  246. }
  247. }
  248. self.listView.updateActiveAnnotations(newAnnonations)
  249. }
  250. }
  251. @IBAction func doneSearchAction(_ sender: Any) {
  252. self.searchTextField.stringValue = ""
  253. self.searchResults = [];
  254. self.reloadData()
  255. self.delegate?.searchDoneAction?(viewController: self)
  256. self.doneButton.isHidden = true
  257. //清空搜索词汇
  258. self.previousSearchString = ""
  259. }
  260. @IBAction func searchHistoryAction(sender: NSMenuItem) {
  261. // self.delegate?.searchAction?(searchString: sender.title, isCase:self.isCase)
  262. self.searchTextField.stringValue = sender.title
  263. self.searchDoneAction()
  264. }
  265. @IBAction func caseSetAction(sender:Any) {
  266. self.isCase = !self.isCase
  267. UserDefaults.standard.set(self.isCase, forKey: "CPDFOfficeSearchIgnoreCaseKey")
  268. self.updateSearchMenu()
  269. self.searchDoneAction()
  270. }
  271. @IBAction func clearSearchHistoryAction(sender:Any) {
  272. UserDefaults.standard.removeObject(forKey: CPDFOfficeSearchHistoryKey)
  273. self.updateSearchMenu()
  274. }
  275. @IBAction func escButtonAction(_ sender: Any) {
  276. self.cancelSelect()
  277. }
  278. //MARK: 跳转
  279. //跳转到指定位置 若存在多个 则跳转最后一个
  280. func previewToSections() {
  281. if outlineView.selectedRowIndexes.count != 0 {
  282. var rows: [KMSearchMode] = []
  283. for index in outlineView.selectedRowIndexes {
  284. let model: KMSearchMode = outlineView.item(atRow: index) as! KMSearchMode
  285. rows.append(model)
  286. }
  287. self.toSearchModes(rows)
  288. }
  289. }
  290. func toSearchModes(_ searchModes: [KMSearchMode]) {
  291. self.selectAllSearchModel()
  292. var selections: [CPDFSelection] = []
  293. for model in searchModes {
  294. model.selection.setColor(NSColor.km_init(hex: "#FF5C00").withAlphaComponent(0.5))
  295. selections.append(model.selection)
  296. }
  297. self.toSections(selections)
  298. }
  299. func toSections(_ selections: [CPDFSelection]) {
  300. self.listView.go(to: selections.last, animated: true)
  301. // if selections.count == 1 {
  302. // self.listView.setHighlightedSelection(selections.first, animated: true)
  303. // } else {
  304. // self.listView.setHighlightedSelections(selections)
  305. // }
  306. self.listView.setNeedsDisplayAnnotationViewForVisiblePages()
  307. }
  308. func didSelectItem(view: KMSearchTableRowView, event: NSEvent) {
  309. let rowView: KMSearchTableRowView = view
  310. if rowView.model.datas.count == 0 {
  311. //当选中一个时
  312. if self.outlineView.selectedRowIndexes.count == 1 || (!event.modifierFlags.contains(NSEvent.ModifierFlags.command) &&
  313. !event.modifierFlags.contains(NSEvent.ModifierFlags.shift)) {
  314. let index = self.outlineView.row(for: rowView)
  315. self.outlineView.selectRowIndexes(IndexSet(integer: IndexSet.Element(index)), byExtendingSelection: false)
  316. }
  317. //原始数据置空
  318. for model in self.selectItems {
  319. model.select = false
  320. self.outlineView.reloadItem(model)
  321. }
  322. //获取最新数据
  323. var items: [KMSearchMode] = []
  324. for index in self.outlineView.selectedRowIndexes {
  325. let model: KMSearchMode = self.outlineView.item(atRow: index) as! KMSearchMode
  326. model.select = true
  327. self.outlineView.reloadItem(model)
  328. items.append(model)
  329. }
  330. self.selectItems = items
  331. //刷新数据
  332. self.previewToSections()
  333. } else {
  334. let expanded = outlineView.isItemExpanded(outlineView.item(atRow: outlineView.selectedRow))
  335. if expanded {
  336. outlineView.collapseItem(outlineView.item(atRow: outlineView.selectedRow), collapseChildren: true)
  337. rowView.model.select = false
  338. outlineView.reloadItem(outlineView.item(atRow: outlineView.selectedRow))
  339. } else {
  340. outlineView.expandItem(outlineView.item(atRow: outlineView.selectedRow), expandChildren: true)
  341. rowView.model.select = true
  342. outlineView.reloadItem(outlineView.item(atRow: outlineView.selectedRow))
  343. }
  344. }
  345. }
  346. func cancelSelect() {
  347. self.outlineView.deselectAll(nil)
  348. for model in self.selectItems {
  349. model.select = false
  350. self.outlineView.reloadItem(model)
  351. }
  352. }
  353. }
  354. // MARK - NSOutlineViewDataSource,NSOutlineViewDelegate
  355. extension KMSearchViewController : NSOutlineViewDataSource,NSOutlineViewDelegate {
  356. func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
  357. let indexModel = item as? KMSearchMode
  358. var count = 0
  359. if indexModel == nil {
  360. count = self.sortResults.count;
  361. } else {
  362. count = indexModel?.datas.count ?? 0
  363. }
  364. if(count == 0) { //无数据时的图
  365. self.emptyView.isHidden = false
  366. } else {
  367. self.emptyView.isHidden = true
  368. }
  369. return count
  370. }
  371. func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
  372. let indexModel = item as? KMSearchMode
  373. var child = KMSearchMode()
  374. if indexModel == nil {
  375. child = self.sortResults[index];
  376. } else {
  377. child = indexModel?.datas[index] ?? KMSearchMode()
  378. }
  379. return child
  380. }
  381. func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
  382. let newitem = item as? KMSearchMode
  383. return newitem?.datas.count ?? 0 > 0
  384. }
  385. func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item:Any) -> NSView? {
  386. let cell : KMSearchCellView = KMSearchCellView.init()
  387. let model : KMSearchMode = item as! KMSearchMode
  388. cell.model = model
  389. return cell
  390. }
  391. func outlineView(_ outlineView: NSOutlineView, rowViewForItem item: Any) -> NSTableRowView? {
  392. let rowView = KMSearchTableRowView()
  393. rowView.model = (item as! KMSearchMode)
  394. rowView.mouseDownCallback = { [unowned self] view, event in
  395. self.didSelectItem(view: view, event: event)
  396. }
  397. rowView.hoverCallback = { [weak self] mouseEntered, mouseBox in
  398. self?.outlineView.enumerateAvailableRowViews { view, row in
  399. if view is KMSearchTableRowView {
  400. (view as? KMSearchTableRowView)?.model.hover = false
  401. (view as? KMSearchTableRowView)?.reloadData()
  402. }
  403. }
  404. if mouseEntered {
  405. rowView.model.hover = true
  406. } else {
  407. rowView.model.hover = false
  408. }
  409. }
  410. return rowView
  411. }
  412. func outlineView(_ outlineView: NSOutlineView, heightOfRowByItem item: Any) -> CGFloat {
  413. let model : KMSearchMode = item as! KMSearchMode
  414. if model.datas.count != 0 {
  415. return 40
  416. } else {
  417. let string: NSString = model.attributedString.string as NSString
  418. let text = string
  419. let size = CGSize(width: outlineView.frame.width - 32, height: 1000)
  420. let options = NSString.DrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
  421. let paragraphStyle = NSMutableParagraphStyle()
  422. paragraphStyle.firstLineHeadIndent = 10.0
  423. paragraphStyle.headIndent = 10.0
  424. paragraphStyle.lineBreakMode = .byCharWrapping
  425. paragraphStyle.lineHeightMultiple = 1.32
  426. let estimatedFrame = NSString(string: text).boundingRect(with: size, options: options, attributes: [NSAttributedString.Key.font: NSFont.SFProTextRegularFont(14.0),
  427. NSAttributedString.Key.paragraphStyle: paragraphStyle], context: nil)
  428. return estimatedFrame.size.height + 16
  429. }
  430. }
  431. // func outlineView(_ outlineView: NSOutlineView, isGroupItem item: Any) -> Bool {
  432. // return true
  433. // }
  434. func outlineView(_ outlineView: NSOutlineView, shouldSelectItem item: Any) -> Bool {
  435. return true
  436. }
  437. func outlineViewSelectionDidChange(_ notification: Notification) {
  438. if self.outlineView.selectedRow == -1 {
  439. self.cancelSelect()
  440. }
  441. }
  442. func outlineView(_ outlineView: NSOutlineView, shouldExpandItem item: Any) -> Bool {
  443. if let item = item as? KMSearchMode {
  444. if !item.select && item.datas.count > 0 {
  445. item.select = true
  446. outlineView.animator().expandItem(item, expandChildren: true)
  447. return false
  448. }
  449. }
  450. return true
  451. }
  452. func outlineView(_ outlineView: NSOutlineView, shouldCollapseItem item: Any) -> Bool {
  453. if let item = item as? KMSearchMode {
  454. if item.select && item.datas.count > 0 {
  455. item.select = false
  456. outlineView.animator().collapseItem(item, collapseChildren: true)
  457. return false
  458. }
  459. }
  460. return true
  461. }
  462. // func outlineView(_ outlineView: NSOutlineView, writeItems items: [Any], to pasteboard: NSPasteboard) -> Bool {
  463. // if self.outlineView.selectedRowIndexes.count > 1 {
  464. // return false
  465. // }
  466. //
  467. // let indexSet = [self.outlineView.clickedRow]
  468. // let indexSetData : Data = NSKeyedArchiver.archivedData(withRootObject: indexSet) as Data
  469. // pasteboard.declareTypes([NSPasteboard.PasteboardType(rawValue: "kKMPDFViewOutlineDragDataType")], owner: self)
  470. // pasteboard.setData(indexSetData, forType: NSPasteboard.PasteboardType(rawValue: NSPasteboard.PasteboardType.RawValue("kKMPDFViewOutlineDragDataType")))
  471. // return true
  472. // }
  473. //
  474. // func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
  475. // var dragOperation = NSDragOperation.init(rawValue: 0)
  476. // if index > 0 {
  477. // dragOperation = NSDragOperation.move
  478. // }
  479. // return dragOperation
  480. // }
  481. //
  482. // func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
  483. // if ((index < 0)) {
  484. // return false
  485. // }
  486. // let outline = item as! CPDFOutline
  487. // if outline.parent == nil {
  488. //
  489. // } else {
  490. //
  491. // }
  492. //
  493. // return true
  494. // }
  495. }
  496. //MARK: ControlTextDelegate
  497. extension KMSearchViewController: NSTextFieldDelegate {
  498. func controlTextDidEndEditing(_ obj: Notification) {
  499. let object = obj.object as! NSTextField
  500. if object == self.searchTextField {
  501. // self.searchDoneAction()
  502. // self.sortResults = []
  503. // self.reloadData()
  504. }
  505. }
  506. func controlTextDidChange(_ obj: Notification) {
  507. let object = obj.object as! NSTextField
  508. if object == self.searchTextField {
  509. if self.searchTextField.stringValue == "" {
  510. self.doneButton.isHidden = true
  511. self.searchResults = []
  512. self.reloadData()
  513. self.cancelAllSearchModel()
  514. }
  515. }
  516. }
  517. func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
  518. switch commandSelector {
  519. case #selector(NSResponder.insertNewline(_:)):
  520. if let inputView = control as? NSTextField {
  521. //当当前TextField按下enter
  522. if inputView == searchTextField {
  523. self.searchDoneAction()
  524. }
  525. }
  526. return true
  527. default:
  528. return false
  529. }
  530. }
  531. }
  532. extension KMSearchViewController: NSMenuDelegate, NSMenuItemValidation {
  533. //MARK: NSMenuItemValidation
  534. func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
  535. let action = menuItem.action
  536. if (action == #selector(addAnonationStyle)) {
  537. let model : KMSearchMode = self.outlineView.item(atRow: self.outlineView.clickedRow) as! KMSearchMode
  538. return model.datas.count == 0
  539. }
  540. return true
  541. }
  542. }
  543. class FocusAwareSearchTextField: NSSearchField {
  544. var onFocus: () -> Void = {}
  545. var onUnfocus: () -> Void = {}
  546. override func becomeFirstResponder() -> Bool {
  547. onFocus()
  548. let textView = window?.fieldEditor(true, for: nil) as? NSTextView
  549. textView?.insertionPointColor = NSColor.km_init(hex: "#252629")
  550. return super.becomeFirstResponder()
  551. }
  552. override func resignFirstResponder() -> Bool {
  553. onUnfocus()
  554. return super.resignFirstResponder()
  555. }
  556. }