KMBotaSearchViewController.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. //
  2. // KMBotaSearchViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by tangchao on 2023/11/16.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. extension KMNSearchKey.wholeWords {
  10. static let botaSearch = "BotaSearchWholeWordsKey"
  11. }
  12. extension KMNSearchKey.caseSensitive {
  13. static let botaSearch = "BotaSearchCaseSensitiveKey"
  14. }
  15. enum KMNBotaSearchType: Int {
  16. case search = 1
  17. case replace = 2
  18. }
  19. @objc protocol KMBotaSearchViewControllerDelegate: NSObjectProtocol {
  20. @objc optional func switchSearchPopWindow(controller: KMBotaSearchViewController)
  21. }
  22. class KMBotaSearchViewController: KMNBotaBaseViewController {
  23. @IBOutlet weak var searchField: NSSearchField!
  24. @IBOutlet weak var segmentedControl: KMSegmentedControl!
  25. @IBOutlet weak var topView: NSBox!
  26. @IBOutlet weak var topHeightConst: NSLayoutConstraint!
  27. var contentView: NSView? {
  28. didSet {
  29. if let view = self.contentView {
  30. self.box.contentView = view
  31. }
  32. }
  33. }
  34. @IBOutlet weak var emptyBox: NSBox!
  35. @IBOutlet weak var searchBox: KMBox!
  36. @IBOutlet weak var searchResultsView: NSView!
  37. @IBOutlet weak var searchResultsLabel: NSTextField!
  38. @IBOutlet weak var searchDomeButton: NSButton!
  39. @IBOutlet weak var box: NSBox!
  40. @IBOutlet weak var emptySearchLabel: NSTextField!
  41. @IBOutlet weak var searchLabel: NSTextField!
  42. @IBOutlet weak var searchTips: NSTextField!
  43. @IBOutlet weak var pageLabel: NSTextField!
  44. @IBOutlet var scrollView: NSScrollView!
  45. @IBOutlet weak var tableView: KMBotaTableView!
  46. private lazy var topContentView_: KMNBotaSearchTopView? = {
  47. let view = KMNBotaSearchTopView.createFromNib()
  48. return view
  49. }()
  50. private var emptyView_: ComponentEmpty = {
  51. let view = ComponentEmpty()
  52. // , image: NSImage(named: "KMImageNameOutlineEmpty")
  53. view.properties = ComponentEmptyProperty(emptyType: .noSearch, state: .normal, text: KMLocalizedString("No Results"), subText: KMLocalizedString(""))
  54. return view
  55. }()
  56. private var menuGroupView_: ComponentGroup?
  57. private var menuSections_: [CPDFSelection] = []
  58. private var menuType_: CAnnotationType = .circle
  59. var handdler = KMNSearchHanddler()
  60. weak var delegate: KMBotaSearchViewControllerDelegate?
  61. var searchResults : [KMBotaSearchSectionModel] = [] {
  62. didSet {
  63. self.updataLeftSideFindView()
  64. }
  65. }
  66. private var datas: [Any] = []
  67. deinit {
  68. KMPrint("KMBotaSearchViewController deinit.")
  69. NotificationCenter.default.removeObserver(self)
  70. }
  71. override func loadView() {
  72. super.loadView()
  73. topView.borderWidth = 0
  74. topView.fillColor = .clear
  75. topView.contentView = topContentView_
  76. topContentView_?.itemClick = { [unowned self] idx, params in
  77. if idx == KMNBotaSearchTopItemKey.search.rawValue {
  78. if let data = params.first as? ComponentButton {
  79. showSearchGroupView(sender: data)
  80. }
  81. } else if idx == KMNBotaSearchTopItemKey.replace.rawValue {
  82. if handdler.type == .search {
  83. handdler.type = .replace
  84. showReplaceView()
  85. } else {
  86. handdler.type = .search
  87. showSearchView()
  88. }
  89. } else if idx == KMNBotaSearchTopItemKey.switch.rawValue {
  90. delegate?.switchSearchPopWindow?(controller: self)
  91. } else if idx == KMNBotaSearchTopItemKey.previous.rawValue {
  92. tableViewMoveUp(tableView)
  93. } else if idx == KMNBotaSearchTopItemKey.next.rawValue {
  94. tableViewMoveDown(tableView)
  95. }
  96. }
  97. showSearchView()
  98. topContentView_?.valueDidChange = { [unowned self] sender, info in
  99. guard let string = info?[.newKey] as? String else {
  100. return
  101. }
  102. let isCase = KMDataManager.ud_bool(forKey: KMNSearchKey.caseSensitive.botaSearch)
  103. let isWholeWord = KMDataManager.ud_bool(forKey: KMNSearchKey.wholeWords.botaSearch)
  104. handdler.search(keyword: string, isCase: isCase, isWholeWord: isWholeWord) { [unowned self] results in
  105. searchResults = results ?? []
  106. showResult()
  107. tableView.reloadData()
  108. }
  109. }
  110. emptyBox.contentView?.addSubview(emptyView_)
  111. emptyView_.km_add_top_constraint(constant: 232)
  112. emptyView_.km_add_bottom_constraint()
  113. emptyView_.km_add_leading_constraint()
  114. emptyView_.km_add_trailing_constraint()
  115. self.emptySearchLabel.stringValue = KMLocalizedString("")
  116. self.emptySearchLabel.textColor = KMAppearance.Layout.h1Color()
  117. self.emptyBox.fillColor = KMAppearance.Layout.l0Color()
  118. // self.searchLabel.stringValue = KMLocalizedString("Search")
  119. // self.searchLabel.textColor = KMAppearance.Layout.h0Color()
  120. // self.searchTips.stringValue = KMLocalizedString("Search")
  121. // self.searchTips.textColor = KMAppearance.Layout.h2Color()
  122. // self.searchResultsLabel.textColor = KMAppearance.Layout.h1Color()
  123. // self.pageLabel.stringValue = KMLocalizedString("Page")
  124. // self.pageLabel.textColor = KMAppearance.Layout.h1Color()
  125. // self.searchResultsView.isHidden = true
  126. // self.searchDomeButton.title = KMLocalizedString("Done")
  127. // self.searchDomeButton.toolTip = KMLocalizedString("Done")
  128. // self.searchDomeButton.setTitleColor(KMAppearance.Layout.w0Color())
  129. // self.searchDomeButton.wantsLayer = true
  130. // self.searchDomeButton.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor
  131. // self.searchDomeButton.layer?.cornerRadius = 4.0
  132. // self.searchDomeButton.hidden = YES;
  133. // self.searchField.wantsLayer = true
  134. // self.searchField.layer.backgroundColor = [KMAppearance KMColor_Layout_L1].CGColor;
  135. // self.searchField.layer?.cornerRadius = 1.0
  136. // self.searchField.layer?.borderWidth = 1.0
  137. // self.searchField.layer?.borderColor = KMAppearance.Interactive.a0Color().cgColor
  138. // self.searchBox.fillColor = KMAppearance.Interactive.s0Color()
  139. // self.searchField.hidden = YES;
  140. // self.searchBox.downCallback = { [unowned self] downEntered, box, _ in
  141. // if (downEntered) {
  142. // self.searchField.isHidden = false
  143. // self.searchDomeButton.isHidden = false
  144. // self.searchBox.isHidden = true
  145. // self.searchField.becomeFirstResponder()
  146. // }
  147. // }
  148. // self.searchBox.isHidden = true
  149. contentView = tableView.enclosingScrollView
  150. tableView.menuClickedAction = { [unowned self] point in
  151. let idxs = self.tableView.selectedRowIndexes.count
  152. let convertP = self.tableView.convert(point, from: nil)
  153. let row = self.tableView.row(at: convertP)
  154. if row == -1 {
  155. return NSMenu()
  156. }
  157. guard let model = self.datas[row] as? KMSearchMode else {
  158. return NSMenu()
  159. }
  160. var viewHeight: CGFloat = 0
  161. let items: [String] = ["Add New Circle", "Add New Rectangle", "Add New Highlight", "Add New Underline", "Add New Strikethrough"]
  162. var menuItemArr: [ComponentMenuitemProperty] = []
  163. for value in items {
  164. let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  165. itemSelected: false,
  166. isDisabled: false,
  167. keyEquivalent: nil,
  168. text: KMLocalizedString(value),
  169. identifier: value)
  170. menuItemArr.append(properties_Menuitem)
  171. viewHeight += 36
  172. }
  173. self.menuGroupView_ = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
  174. self.menuGroupView_?.clickedAutoHide = false
  175. self.menuGroupView_?.groupDelegate = self
  176. self.menuGroupView_?.frame = CGRectMake(0, 0, 180, viewHeight)
  177. self.menuGroupView_?.updateGroupInfo(menuItemArr)
  178. self.menuSections_ = [model.selection]
  179. self.menuGroupView_?.showWithPoint(CGPoint(x: point.x, y: point.y - viewHeight), relativeTo: self.tableView)
  180. return NSMenu()
  181. }
  182. // var rowIndexes = self.findTableView.selectedRowIndexes
  183. // let row = self.findTableView.clickedRow
  184. // if (row != -1) {
  185. // if rowIndexes.contains(row) == false {
  186. // rowIndexes = IndexSet(integer: row)
  187. // }
  188. //
  189. // var selections: [CPDFSelection] = []
  190. // for (i, data) in self.searchResults.enumerated() {
  191. // if rowIndexes.contains(i) {
  192. // selections.append(data.selection)
  193. // }
  194. // }
  195. // let hideNotes = self.hideNotes()
  196. // let allowsNotes = self.allowsNotes()
  197. // if hideNotes == false && allowsNotes {
  198. // item = menu.addItem(withTitle: KMLocalizedString("Add New Circle"), action: #selector(addAnnotationsForSelections), target: self, tag: CAnnotationType.circle.rawValue)
  199. // item?.representedObject = selections
  200. // item = menu.addItem(withTitle: KMLocalizedString("Add New Rectangle"), action: #selector(addAnnotationsForSelections), target: self, tag: CAnnotationType.square.rawValue)
  201. // item?.representedObject = selections
  202. // item = menu.addItem(withTitle: KMLocalizedString("Add New Highlight"), action: #selector(addAnnotationsForSelections), target: self, tag: CAnnotationType.highlight.rawValue)
  203. // item?.representedObject = selections
  204. // item = menu.addItem(withTitle: KMLocalizedString("Add New Underline"), action: #selector(addAnnotationsForSelections), target: self, tag: CAnnotationType.underline.rawValue)
  205. // item?.representedObject = selections
  206. // item = menu.addItem(withTitle: KMLocalizedString("Add New Strikethrough"), action: #selector(addAnnotationsForSelections), target: self, tag: CAnnotationType.strikeOut.rawValue)
  207. // item?.representedObject = selections
  208. // }
  209. // }
  210. }
  211. override func viewDidLoad() {
  212. super.viewDidLoad()
  213. self.tableView.delegate = self
  214. self.tableView.dataSource = self
  215. self.tableView.botaDelegate = self
  216. // self.tableView.menu?.delegate = self
  217. // self.mwcFlags.wholeWordSearch = KMDataManager.ud_integer(forKey: SKWholeWordSearchKey)
  218. // self.mwcFlags.caseInsensitiveSearch = KMDataManager.ud_integer(forKey: SKCaseInsensitiveSearchKey)
  219. // self.tableView.backgroundColor = KMAppearance.Layout.l0Color()
  220. self.tableView.tableColumn(withIdentifier: kPageColumnId)?.headerCell.title = KMLocalizedString("Page")
  221. }
  222. override func viewDidAppear() {
  223. super.viewDidAppear()
  224. // self.searchField.becomeFirstResponder()
  225. self.updateViewColor()
  226. DistributedNotificationCenter.default().addObserver(self, selector: #selector(themeChanged), name: NSApplication.interfaceThemeChangedNotification, object: nil)
  227. }
  228. override func updateUILanguage() {
  229. super.updateUILanguage()
  230. KMMainThreadExecute {
  231. self.topContentView_?.resultLabel.stringValue = KMLocalizedString("Result:") + " " + "\(self.handdler.searchResults.count)"
  232. self.tableView.reloadData()
  233. }
  234. }
  235. override func updateUIThemeColor() {
  236. super.updateUIThemeColor()
  237. KMMainThreadExecute {
  238. self.view.wantsLayer = true
  239. let color = KMNColorTools.colorBg_layoutMiddle()
  240. self.view.layer?.backgroundColor = color.cgColor
  241. self.tableView.backgroundColor = color
  242. self.topContentView_?.resultLabel.textColor = KMNColorTools.colorText_3()
  243. self.tableView.reloadData()
  244. }
  245. }
  246. func updateViewColor() {
  247. if (KMAppearance.isDarkMode()) {
  248. // self.searchField.layer?.backgroundColor = NSColor(red: 57.0/255.0, green: 60.0/255.0, blue: 62.0/255.0, alpha: 1).cgColor
  249. } else {
  250. // self.searchField.layer?.backgroundColor = .white
  251. }
  252. }
  253. func showSearchView() {
  254. topContentView_?.showSearch()
  255. topHeightConst.constant = topContentView_?.fetchContentHeight(type: handdler.type, hasResult: handdler.searchResults.isEmpty == false) ?? 0
  256. }
  257. func showReplaceView() {
  258. topContentView_?.showReplace()
  259. topHeightConst.constant = topContentView_?.fetchContentHeight(type: handdler.type, hasResult: handdler.searchResults.isEmpty == false) ?? 0
  260. }
  261. func showResult() {
  262. topContentView_?.showResult(type: handdler.type)
  263. topContentView_?.resultLabel.stringValue = KMLocalizedString("Result:") + " " + "\(self.handdler.searchResults.count)"
  264. topHeightConst.constant = topContentView_?.fetchContentHeight(type: handdler.type, hasResult: searchResults.isEmpty == false) ?? 0
  265. }
  266. // MARK: - Group View
  267. func showSearchGroupView(sender: ComponentButton) {
  268. var viewHeight: CGFloat = 8
  269. var menuItemArr: [ComponentMenuitemProperty] = []
  270. let titles = ["Search", "Find and Replace", "", "Whole Words", "Case Sensitive"]
  271. for i in titles {
  272. if i.isEmpty {
  273. let menuI = ComponentMenuitemProperty.divider()
  274. menuItemArr.append(menuI)
  275. viewHeight += 8
  276. } else {
  277. let menuI = ComponentMenuitemProperty(text: KMLocalizedString(i))
  278. menuItemArr.append(menuI)
  279. viewHeight += 36
  280. }
  281. }
  282. if handdler.type == .search {
  283. menuItemArr.first?.righticon = NSImage(named: "KMNImageNameMenuSelect")
  284. } else if handdler.type == .replace {
  285. let info = menuItemArr.safe_element(for: 1) as? ComponentMenuitemProperty
  286. info?.righticon = NSImage(named: "KMNImageNameMenuSelect")
  287. }
  288. if let info = menuItemArr.safe_element(for: 3) as? ComponentMenuitemProperty {
  289. if KMDataManager.ud_bool(forKey: KMNSearchKey.wholeWords.botaSearch) {
  290. info.righticon = NSImage(named: "KMNImageNameMenuSelect")
  291. }
  292. }
  293. if let info = menuItemArr.last {
  294. if KMDataManager.ud_bool(forKey: KMNSearchKey.caseSensitive.botaSearch) {
  295. info.righticon = NSImage(named: "KMNImageNameMenuSelect")
  296. }
  297. }
  298. let groupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
  299. searchGroupView = groupView
  300. groupView?.groupDelegate = self
  301. groupView?.frame = CGRectMake(310, 0, 200, viewHeight)
  302. groupView?.updateGroupInfo(menuItemArr)
  303. var point = sender.convert(sender.frame.origin, to: nil)
  304. point.y -= viewHeight
  305. groupView?.showWithPoint(point, relativeTo: sender)
  306. searchGroupTarget = sender
  307. }
  308. @objc func themeChanged(_ notification: NSNotification) {
  309. DispatchQueue.main.asyncAfter(deadline: .now()+0.3) {
  310. self.updateViewColor()
  311. }
  312. }
  313. @IBAction func searchDomeButtonAtion(_ sender: AnyObject) {
  314. self.searchField.isHidden = true
  315. self.searchDomeButton.isHidden = true
  316. self.searchBox.isHidden = false
  317. }
  318. @objc func toggleWholeWordSearch(_ sender: AnyObject?) {
  319. // if self.mwcFlags.wholeWordSearch == 1 {
  320. // self.mwcFlags.wholeWordSearch = 0
  321. // } else {
  322. // self.mwcFlags.wholeWordSearch = 1
  323. // }
  324. // if self.searchField.stringValue.isEmpty == false {
  325. // self.search(self.searchField)
  326. // }
  327. // KMDataManager.ud_set(self.mwcFlags.wholeWordSearch, forKey: SKWholeWordSearchKey)
  328. }
  329. @objc func toggleCaseInsensitiveSearch(_ sender: AnyObject?) {
  330. // if self.mwcFlags.caseInsensitiveSearch == 0 {
  331. // self.mwcFlags.caseInsensitiveSearch = 1
  332. // } else {
  333. // self.mwcFlags.caseInsensitiveSearch = 0
  334. // }
  335. //
  336. // if self.searchField.stringValue.isEmpty == false {
  337. // self.search(self.searchField)
  338. // }
  339. // KMDataManager.ud_set(self.mwcFlags.caseInsensitiveSearch, forKey: SKCaseInsensitiveSearchKey)
  340. }
  341. @objc func goToSelectedFindResults(_ sender: AnyObject?) {
  342. // guard let olView = sender as? NSTableView, olView.clickedRow != -1 else {
  343. // NSSound.beep()
  344. // return
  345. // }
  346. // self.updateFindResultHighlightsForDirection(.directSelection)
  347. }
  348. @objc func searchAction(_ sender: NSSearchField) {
  349. // if sender.stringValue.isEmpty {
  350. // self.applySearchTableHeader("")
  351. // }
  352. // self.delegate?.searchAction?(searchString: sender.stringValue, isCase: self.mwcFlags.caseInsensitiveSearch == 1)
  353. handdler.search(keyword: sender.stringValue, isCase: false, isWholeWord: false) { [weak self] results in
  354. self?.searchResults = results ?? []
  355. self?.tableView.reloadData()
  356. }
  357. }
  358. @objc func addAnnotationsForSelections(_ sender: NSMenuItem) {
  359. for selection in menuSections_ {
  360. // self.listView?.addAnnotation(with: CAnnotationType(rawValue: sender.tag) ?? .circle, selection: selection, page: selection.page, bounds: selection.bounds)
  361. }
  362. }
  363. func updataLeftSideFindView() {
  364. if (self.searchResults.count > 0) {
  365. self.emptyBox.isHidden = true
  366. // self.searchResultsView.isHidden = false
  367. // self.searchResultsLabel.stringValue = String(format: KMLocalizedString("%ld Results"), self.searchResults.count)
  368. } else {
  369. self.emptyBox.isHidden = false
  370. // self.searchResultsView.isHidden = true
  371. }
  372. }
  373. }
  374. // MARK: - NSTableViewDelegate, NSTableViewDataSource
  375. extension KMBotaSearchViewController: NSTableViewDelegate, NSTableViewDataSource {
  376. func numberOfRows(in tableView: NSTableView) -> Int {
  377. var datas: [Any] = []
  378. for sectionM in self.handdler.searchResults {
  379. if sectionM.items.count > 0 {
  380. datas.append(sectionM)
  381. if sectionM.isExpand == false {
  382. continue
  383. }
  384. for item in sectionM.items {
  385. datas.append(item)
  386. }
  387. }
  388. }
  389. self.datas = datas
  390. return datas.count
  391. }
  392. func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
  393. let model = self.datas[row]
  394. if let data = model as? KMBotaSearchSectionModel {
  395. var cell = tableView.makeView(withIdentifier: KMSectionCellView.km_identifier, owner: nil) as? KMSectionCellView
  396. if cell == nil {
  397. cell = KMSectionCellView.createFromNib()
  398. }
  399. cell?.titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium")
  400. cell?.titleLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-regular")
  401. cell?.titleLabel.textColor = KMNColorTools.colorText_1()
  402. cell?.countLabel.textColor = KMNColorTools.colorText_3()
  403. cell?.isExpand = data.isExpand
  404. let pageIndex = data.pageIndex
  405. cell?.titleLabel.stringValue = KMLocalizedString("Page") + " \(pageIndex + 1)"
  406. cell?.countLabel.stringValue = "\(data.itemCount)"
  407. cell?.bottomLine.wantsLayer = true
  408. cell?.bottomLine.layer?.backgroundColor = KMNColorTools.colorBorder_divider().cgColor
  409. cell?.itemClick = { [weak self] idx, _ in
  410. if idx == 1 { // 收取 & 展开
  411. data.isExpand = !data.isExpand
  412. self?.tableView.reloadData()
  413. }
  414. }
  415. return cell
  416. }
  417. if let data = model as? KMSearchMode {
  418. var cell = tableView.makeView(withIdentifier: KMNBotaSearchCellView.km_identifier, owner: self) as? KMNBotaSearchCellView
  419. if cell == nil {
  420. cell = KMNBotaSearchCellView()
  421. }
  422. cell?.label.attributedStringValue = data.attributedString
  423. return cell
  424. }
  425. return nil
  426. }
  427. func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
  428. let model = datas[row]
  429. if model is KMBotaSearchSectionModel {
  430. return 40.0
  431. }
  432. if let data = model as? KMSearchMode {
  433. let width = NSWidth(self.view.frame)
  434. let rect = data.attributedString.boundingRect(with: .init(width: width-24*2, height: CGFLOAT_MAX), options: [.usesLineFragmentOrigin, .usesLineFragmentOrigin])
  435. return rect.size.height + 12 * 2
  436. }
  437. return 40.0
  438. }
  439. func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
  440. let rowView = KMBotaTableRowView()
  441. return rowView
  442. }
  443. func tableViewSelectionDidChange(_ notification: Notification) {
  444. // if self.stopRepeatLoad == true {
  445. //
  446. // } else {
  447. // self.delegate?.controller?(controller: self, listViewSelectionDidChange: notification.object, info: nil)
  448. // }
  449. // [self updateFindResultHighlightsForDirection:NSDirectSelection];
  450. let row = self.tableView.selectedRow
  451. if row >= 0 {
  452. // let model = handdler.searchResults[row]
  453. // let isEditing = self.listView?.isEditing() ?? false
  454. // if isEditing {
  455. // self.mainViewController?.srHanddler.showSelection(model.selection)
  456. // return
  457. // }
  458. // self.listView?.go(to: model.selection, animated: true)
  459. // self.listView?.setHighlightedSelection(model.selection, animated: true)
  460. DispatchQueue.main.asyncAfter(deadline: .now()+0.3) {
  461. // self.listView?.setHighlightedSelections([model.selection])
  462. // self.listView?.setNeedsDisplayAnnotationViewForVisiblePages()
  463. }
  464. }
  465. }
  466. func tableView(_ aTableView: NSTableView, copyRowsWithIndexes rowIndexes: IndexSet) {
  467. if IAPProductsManager.default().isAvailableAllFunction() == false {
  468. KMPurchaseCompareWindowController.sharedInstance().showWindow(nil)
  469. return
  470. }
  471. var string = ""
  472. for idx in rowIndexes {
  473. // let match = handdler.searchResults[idx].selection
  474. // string.append("* ")
  475. // [string appendFormat:NSLocalizedString(@"Page %@", @""), [match firstPageLabel]];
  476. // string = string.appendingFormat(KMLocalizedString("Page %@"), "\(match.safeFirstPage()?.pageIndex() ?? 0)")
  477. // [string appendFormat:@"", [[match contextString] string]];
  478. // string = string.appendingFormat(": %@\n", match.string() ?? "")
  479. }
  480. let pboard = NSPasteboard.general
  481. pboard.clearContents()
  482. pboard.writeObjects([string as NSPasteboardWriting])
  483. }
  484. }
  485. // MARK: - KMBotaTableViewDelegate
  486. extension KMBotaSearchViewController: KMBotaTableViewDelegate {
  487. func tableView(_ aTableView: NSTableView, canCopyRowsWithIndexes rowIndexes: IndexSet) -> Bool {
  488. return rowIndexes.count > 0
  489. }
  490. func tableViewMoveRight(_ aTableView: NSTableView) {
  491. // self.updateFindResultHighlightsForDirection(.selectingNext)
  492. }
  493. func tableViewMoveUp(_ aTableView: NSTableView) {
  494. self.tableView.km_safe_selectRowIndexes(.init(integer: self.tableView.selectedRow-1), byExtendingSelection: false)
  495. self.tableView.scrollRowToVisible(self.tableView.selectedRow)
  496. }
  497. func tableViewMoveDown(_ aTableView: NSTableView) {
  498. self.tableView.km_safe_selectRowIndexes(.init(integer: self.tableView.selectedRow+1), byExtendingSelection: false)
  499. self.tableView.scrollRowToVisible(self.tableView.selectedRow)
  500. }
  501. func tableView(_ aTableView: NSTableView, imageContextForRow rowIndex: Int) -> AnyObject? {
  502. if rowIndex >= self.searchResults.count {
  503. return nil
  504. }
  505. // let model = self.searchResults[rowIndex]
  506. // let selection = model.selection
  507. // let x = selection.bounds.origin.x + NSWidth(selection.bounds) * 0.5
  508. // let y = selection.bounds.origin.y + NSHeight(selection.bounds) * 0.5
  509. // let point = NSPoint(x: x, y: y)
  510. // return CPDFDestination(document: self.pdfDocument(), pageIndex: Int(model.selectionPageIndex), at: point, zoom: self.scaleFactor().cgFloat)
  511. return nil
  512. }
  513. }
  514. //MARK: - ComponentGroupDelegate
  515. extension KMBotaSearchViewController: ComponentGroupDelegate {
  516. func componentGroupDidDismiss(group: ComponentGroup?) {
  517. // if group == groupView_ {
  518. // removeGroupView()
  519. // } else if group == menuGroupView_ {
  520. // group?.removeFromSuperview()
  521. // menuGroupView_ = nil
  522. // } else
  523. if group == searchGroupView {
  524. // searchGroupView_ = nil
  525. searchGroupTarget?.properties.state = .normal
  526. searchGroupTarget?.reloadData()
  527. searchGroupTarget = nil
  528. }
  529. }
  530. func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) {
  531. // if group == groupView_ {
  532. // if let selItem = menuItemProperty {
  533. // let index = group?.menuItemArr.firstIndex(of: selItem)
  534. // if index == 0 {
  535. // expandAllComments(item: NSMenuItem())
  536. // } else if index == 1 {
  537. // collapseAllComments(item: NSMenuItem())
  538. // } else if index == 2 {
  539. // removeAllOutlineItem(item: NSMenuItem())
  540. // }
  541. // }
  542. // } else
  543. if group == menuGroupView_ {
  544. if let selItem = menuItemProperty {
  545. let index = group?.menuItemArr.firstIndex(of: selItem)
  546. if index == 0 {
  547. menuType_ = .circle
  548. addAnnotationsForSelections(NSMenuItem())
  549. } else if index == 1 {
  550. menuType_ = .square
  551. addAnnotationsForSelections(NSMenuItem())
  552. } else if index == 2 {
  553. menuType_ = .highlight
  554. addAnnotationsForSelections(NSMenuItem())
  555. } else if index == 3 {
  556. menuType_ = .underline
  557. addAnnotationsForSelections(NSMenuItem())
  558. } else if index == 4 {
  559. menuType_ = .strikeOut
  560. addAnnotationsForSelections(NSMenuItem())
  561. }
  562. group?.removeFromSuperview()
  563. }
  564. } else if group == searchGroupView {
  565. guard let menuI = menuItemProperty else {
  566. return
  567. }
  568. let idx = group?.menuItemArr.firstIndex(of: menuI)
  569. if idx == 0 { // search
  570. } else if idx == 1 { // replace
  571. } else if idx == 3 {
  572. let key = KMNSearchKey.wholeWords.botaSearch
  573. let value = KMDataManager.ud_bool(forKey: key)
  574. KMDataManager.ud_set(!value, forKey: key)
  575. // BOTAOutlineView.wholeWords = !value
  576. } else if idx == 4 {
  577. let key = KMNSearchKey.caseSensitive.botaSearch
  578. let value = KMDataManager.ud_bool(forKey: key)
  579. KMDataManager.ud_set(!value, forKey: key)
  580. // BOTAOutlineView.caseSensitive = !value
  581. }
  582. }
  583. }
  584. }