KMLeftSideViewController+Note.swift 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. //
  2. // KMLeftSideViewController+Note.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by tangchao on 2023/12/23.
  6. //
  7. import Foundation
  8. extension KMLeftSideViewController.Key {
  9. static let noteAscendSortKey = "KMLeftSideViewAscendSortBoolKey"
  10. static let noteSortTypeKey = "KMLeftSideViewNoteSortTypeKey"
  11. static let noteTableColumn = "KMNoteOutlineViewTableColumnKey"
  12. static let noteFilterPage = "kKMNoteFilterAnnotationPageKey"
  13. static let noteFilterTime = "kKMNoteFilterAnnotationTimeKey"
  14. static let noteFilterAuther = "kKMNoteFilterAnnotationAutherKey"
  15. }
  16. // MARK: - Menu
  17. extension KMLeftSideViewController {
  18. func note_initSubViews() {
  19. self.noteSearchField.backgroundColor = KMAppearance.Layout.l_1Color()
  20. self.noteSearchField.wantsLayer = true
  21. self.noteSearchField.layer?.backgroundColor = KMAppearance.Layout.l_1Color().cgColor
  22. self.noteSearchField.layer?.borderWidth = 1.0
  23. self.noteMoreButton.target = self
  24. self.noteMoreButton.tag = 304
  25. self.noteMoreButton.action = #selector(leftSideViewMoreButtonAction)
  26. self.moreButtonLayer = KMButtonLayer()
  27. self.noteMoreButton.layer?.addSublayer(self.moreButtonLayer!)
  28. self.moreButtonLayer?.frame = CGRectMake(0, 0, CGRectGetWidth(self.noteMoreButton.bounds), CGRectGetHeight(self.noteMoreButton.bounds))
  29. self.noteFilterButton.target = self
  30. self.noteFilterButton.action = #selector(noteFilterAction)
  31. self.filterButtonLayer = NSView()
  32. self.noteFilterButton.addSubview(self.filterButtonLayer!)
  33. self.filterButtonLayer?.frame = CGRectMake(14, 2, 8, 8)
  34. self.noteDoneButton.action = #selector(leftSideViewDoneButtonAction)
  35. self.noteDoneButton.target = self
  36. self.noteDoneButton.tag = 311
  37. self.noteDoneButton.isHidden = true
  38. self.noteSearchField.delegate = self
  39. self.noteSearchField.isHidden = true
  40. self.noteSearchField.endEditCallBack = { [unowned self] isEndEdit in
  41. if (isEndEdit) {
  42. self.noteSearchField.isHidden = true
  43. self.noteSearchButton.isHidden = false
  44. self.noteTitleLabel.isHidden = false
  45. }
  46. }
  47. self.sortTypeBox.downCallback = { [unowned self] downEntered, mouseBox, _ in
  48. if (downEntered) {
  49. let menu = NSMenu()
  50. let timeItem = menu.addItem(title: KMLocalizedString("Time", nil), action: #selector(sortTypeAction), target: self)
  51. timeItem?.representedObject = self
  52. timeItem?.tag = 0
  53. let pageItem = menu.addItem(title: KMLocalizedString("Page", nil), action: #selector(sortTypeAction), target: self)
  54. pageItem?.representedObject = self
  55. timeItem?.tag = 1
  56. if (self.noteSortType == .time) {
  57. timeItem?.state = .on
  58. pageItem?.state = .off
  59. } else if (self.noteSortType == .page) {
  60. timeItem?.state = .off
  61. pageItem?.state = .on
  62. }
  63. menu.popUp(positioning: nil, at: CGPointMake(-10, 0), in: self.sortTypeBox)
  64. }
  65. }
  66. self.noteOutlineView.delegate = self
  67. self.noteOutlineView.dataSource = self
  68. self.noteOutlineView.botaDelegate = self
  69. self.noteOutlineView.botaDataSource = self
  70. self.noteOutlineView.noteDelegate = self
  71. self.noteOutlineView.menu = NSMenu()
  72. self.noteOutlineView.menu?.delegate = self
  73. self.noteOutlineView.typeSelectHelper = SKTypeSelectHelper(matchOption: .SKSubstringMatch)
  74. self.noteOutlineView.registerForDraggedTypes(NSColor.readableTypes(for: NSPasteboard(name: .drag)))
  75. self.noteOutlineView.target = self
  76. self.noteOutlineView.doubleAction = #selector(selectSelectedNote)
  77. }
  78. func note_initDefalutValue() {
  79. self.noteView.wantsLayer = true
  80. self.noteView.layer?.backgroundColor = KMAppearance.Layout.l0Color().cgColor
  81. let sud = UserDefaults.standard
  82. if let dict = sud.dictionary(forKey: Self.Key.noteTableColumn) {
  83. self.noteTypeDict = dict
  84. } else {
  85. self.noteTypeDict = [Self.Key.noteFilterPage : false,
  86. Self.Key.noteFilterTime : false,
  87. Self.Key.noteFilterAuther : false]
  88. sud.sync_setValue(self.noteTypeDict, forKey: Self.Key.noteTableColumn)
  89. }
  90. self.caseInsensitiveNoteSearch = sud.bool(forKey: SKCaseInsensitiveNoteSearchKey)
  91. self.isAscendSort = KMDataManager.ud_bool(forKey: Self.Key.noteAscendSortKey)
  92. self.noteTitleLabel.stringValue = KMLocalizedString("Notes", nil);
  93. self.noteTitleLabel.textColor = KMAppearance.Layout.h0Color()
  94. self.noteSearchField.layer?.borderColor = KMAppearance.Interactive.a0Color().cgColor
  95. self.noteMoreButton.wantsLayer = true
  96. self.moreButtonLayer?.layerType = .none
  97. self.moreButtonLayer?.isHidden = true
  98. self.noteFilterButton.toolTip = KMLocalizedString("Sort", nil)
  99. self.noteFilterButton.wantsLayer = true
  100. self.filterButtonLayer?.isHidden = true
  101. self.filterButtonLayer?.wantsLayer = true
  102. self.filterButtonLayer?.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor
  103. self.filterButtonLayer?.layer?.cornerRadius = 4.0
  104. if (self.isAscendSort) {
  105. self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankReverse)
  106. self.noteSortButton.toolTip = KMLocalizedString("ascending sort", nil)
  107. } else {
  108. self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankPositive)
  109. self.noteSortButton.toolTip = KMLocalizedString("descending sort", nil)
  110. }
  111. self.noteSearchButton.toolTip = KMLocalizedString("Search", nil)
  112. self.noteDoneButton.title = KMLocalizedString("Done", nil)
  113. self.noteDoneButton.toolTip = KMLocalizedString("Done", nil)
  114. self.noteDoneButton.setTitleColor(KMAppearance.Layout.w0Color())
  115. self.noteDoneButton.wantsLayer = true
  116. self.noteDoneButton.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor
  117. self.noteDoneButton.layer?.cornerRadius = 4.0
  118. self.noteHeaderView.wantsLayer = true
  119. self.noteHeaderView.layer?.backgroundColor = KMAppearance.Else.textTagColor().cgColor
  120. self.noteHeaderView.layer?.cornerRadius = 1.0
  121. let sortType = KMDataManager.ud_integer(forKey: Self.Key.noteSortTypeKey)
  122. if (sortType == 1) {
  123. self.noteSortType = KMNoteSortType(rawValue: sortType) ?? .none
  124. if (self.noteSortType == .time) {
  125. self.sortTypeLabel.stringValue = KMLocalizedString("Time", nil)
  126. self.sortTypeBox.toolTip = KMLocalizedString("Time", nil)
  127. } else if (self.noteSortType == .page) {
  128. self.sortTypeLabel.stringValue = KMLocalizedString("Page", nil)
  129. self.sortTypeBox.toolTip = KMLocalizedString("Page", nil)
  130. }
  131. } else {
  132. self.noteSortType = .time
  133. self.sortTypeLabel.stringValue = KMLocalizedString("Time", nil)
  134. }
  135. self.sortTypeLabel.textColor = KMAppearance.Layout.h1Color()
  136. self.noteOutlineView.backgroundColor = KMAppearance.Layout.l0Color()
  137. self.noteOutlineView.autoresizesOutlineColumn = false
  138. self.noteOutlineView.indentationPerLevel = 0
  139. }
  140. @IBAction func note_expandAllComments(_ sender: AnyObject?) {
  141. if (self.foldType == .unfold) { // 已全部展开
  142. return
  143. }
  144. // 设置全部展开的标识
  145. self.foldType = .unfold
  146. // 加载数据
  147. self.loadUnfoldDate(.none)
  148. // 刷新UI
  149. self.noteOutlineView.reloadData()
  150. }
  151. @IBAction func note_foldAllComments(_ sender: AnyObject?) {
  152. if (self.foldType == .fold) {
  153. return
  154. }
  155. self.foldType = .fold
  156. self.loadUnfoldDate(.none)
  157. self.noteOutlineView.reloadData()
  158. }
  159. @IBAction func noteShowNoteAction(_ sender: AnyObject?) {
  160. let item = sender as? NSMenuItem
  161. let tag = item?.tag ?? 0
  162. if (tag == 100) {
  163. } else if (tag == 101) {
  164. let isPage = self.noteTypeDict[Self.Key.noteFilterPage] as? Bool ?? false
  165. self.noteTypeDict[Self.Key.noteFilterPage] = !isPage
  166. } else if (tag == 102) {
  167. let isTime = self.noteTypeDict[Self.Key.noteFilterTime] as? Bool ?? false
  168. self.noteTypeDict[Self.Key.noteFilterTime] = !isTime
  169. } else if (tag == 103) {
  170. let isAuther = self.noteTypeDict[Self.Key.noteFilterAuther] as? Bool ?? false
  171. self.noteTypeDict[Self.Key.noteFilterAuther] = !isAuther
  172. }
  173. UserDefaults.standard.sync_setValue(self.noteTypeDict, forKey: Self.Key.noteTableColumn)
  174. let selectRow = self.noteOutlineView.selectedRow
  175. self.noteOutlineView.reloadData()
  176. self.noteOutlineView.selectRowIndexes(IndexSet(integer: selectRow), byExtendingSelection: false)
  177. }
  178. @objc func exportAnnotationNotes(_ sender: AnyObject?) {
  179. let doc = self.view.window?.windowController?.document as? NSDocument
  180. doc?.saveTo(sender)
  181. }
  182. @objc func leftSideEmptyAnnotationClick_DeleteAnnotation(_ sender: AnyObject?) {
  183. guard let doc = self.listView.document else {
  184. return
  185. }
  186. Task {
  187. let response = await KMAlertTool.runModel(message: KMLocalizedString("This will permanently remove all annotations. Are you sure to continue?", nil), buttons: [KMLocalizedString("Yes", nil), KMLocalizedString("No", nil)])
  188. if response == .alertFirstButtonReturn {
  189. var annos: [CPDFAnnotation] = []
  190. for i in 0 ..< doc.pageCount {
  191. let page = self.listView.document.page(at: i)
  192. for anno in page?.annotations ?? [] {
  193. if anno is CPDFTextWidgetAnnotation || anno is CPDFButtonWidgetAnnotation || anno is CPDFChoiceWidgetAnnotation {
  194. continue
  195. }
  196. // if ([annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeSignature]) {
  197. // continue;
  198. // }
  199. annos.append(anno)
  200. }
  201. }
  202. for anno in annos {
  203. self.listView.remove(anno)
  204. }
  205. self.reloadAnnotation()
  206. }
  207. }
  208. }
  209. @objc func unfoldNoteAction(_ sender: NSMenuItem) {
  210. if sender.state == .on {
  211. return
  212. }
  213. let row = self.noteOutlineView.clickedRow
  214. guard let foldNote = self.fetchNote(for: row) else {
  215. return
  216. }
  217. if self.allFoldNotes.contains(foldNote) == false {
  218. self.allFoldNotes.append(foldNote)
  219. }
  220. if self.allFoldNotes.count == self.canFoldNotes.count {
  221. self.foldType = .unfold
  222. } else {
  223. self.foldType = .none
  224. }
  225. let viewS = self.noteOutlineView.view(atColumn: 0, row: row, makeIfNecessary: true)
  226. (viewS as? KMNoteTableViewCell)?.isFold = false
  227. }
  228. @objc func foldNoteAction(_ sender: NSMenuItem) {
  229. // if sender.state == .on {
  230. // return
  231. // }
  232. let row = self.noteOutlineView.clickedRow
  233. guard let foldNote = self.fetchNote(for: row) else {
  234. return
  235. }
  236. if self.allFoldNotes.contains(foldNote) == false {
  237. self.allFoldNotes.append(foldNote)
  238. }
  239. if (self.allFoldNotes.count == 0) {
  240. self.foldType = .fold
  241. } else {
  242. self.foldType = .none
  243. }
  244. let viewS = self.noteOutlineView.view(atColumn: 0, row: row, makeIfNecessary: true)
  245. (viewS as? KMNoteTableViewCell)?.isFold = true
  246. }
  247. @objc func deleteNotes(_ sender: NSMenuItem) {
  248. self.outlineView(self.noteOutlineView, deleteItems: sender.representedObject as? [Any] ?? [])
  249. }
  250. @objc func removeAllAnnotations(_ sender: AnyObject?) {
  251. self.leftSideEmptyAnnotationClick_DeleteAnnotation(nil)
  252. }
  253. @objc func editNoteTextFromTable(_ sender: NSMenuItem) {
  254. // PDFAnnotation *annotation = [sender representedObject];
  255. guard let annotation = sender.representedObject as? CPDFAnnotation else {
  256. return
  257. }
  258. self.listView.scrollAnnotationToVisible(annotation)
  259. // self.listView.activeAnnotation = annotation
  260. // [self showNote:annotation];
  261. // SKNoteWindowController *noteController = (SKNoteWindowController *)[self windowControllerForNote:annotation];
  262. // [[noteController window] makeFirstResponder:[noteController textView]];
  263. // [[noteController textView] selectAll:nil];
  264. }
  265. @objc func editThisAnnotation(_ sender: AnyObject?) {
  266. KMPrint("editThisAnnotation ...")
  267. }
  268. @objc func editNoteFromTable(_ sender: AnyObject?) {
  269. KMPrint("editNoteFromTable ...")
  270. }
  271. @IBAction func noteSortAction(_ sender: AnyObject?) {
  272. if (self.isAscendSort) {
  273. self.isAscendSort = false
  274. self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankPositive)
  275. self.noteSortButton.toolTip = KMLocalizedString("descending sort", nil)
  276. } else {
  277. self.isAscendSort = true
  278. self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankReverse)
  279. self.noteSortButton.toolTip = KMLocalizedString("ascending sort", nil)
  280. }
  281. KMDataManager.ud_set(self.isAscendSort, forKey: Self.Key.noteAscendSortKey)
  282. // self.annotationSort(sortArray: [])
  283. self.reloadAnnotation()
  284. }
  285. @IBAction func noteSearchAction(_ sender: NSButton) {
  286. self.noteSearchField.isHidden = false
  287. self.noteTitleLabel.isHidden = true
  288. self.noteSearchButton.isHidden = true
  289. self.noteDoneButton.isHidden = false
  290. self.noteFilterButton.isHidden = true
  291. self.noteMoreButton.isHidden = true
  292. self.noteSearchField.becomeFirstResponder()
  293. }
  294. @IBAction func noteFilterAction(_ sender: AnyObject?) {
  295. let button = sender as? NSButton
  296. let menu = NSMenu()
  297. let filterViewController = KMNoteOutlineFilterViewController()
  298. filterViewController.listView = self.listView
  299. filterViewController.view.layer?.backgroundColor = .clear
  300. var notes = NSMutableArray()
  301. // for section in self._annotations {
  302. // if section.annotations?.count != 0 {
  303. // for item in section.annotations! {
  304. // notes.add(item.annotation!)
  305. // }
  306. // }
  307. // }
  308. filterViewController.setNotesArray(self.allAnnotations as NSArray)
  309. filterViewController.applyFilterCallback = { [weak self] typeArr, colorArr, authorArr, isEmpty in
  310. menu.cancelTracking()
  311. if (isEmpty) {
  312. self?.filterButtonLayer?.isHidden = true
  313. } else {
  314. self?.filterButtonLayer?.isHidden = false
  315. }
  316. // self?.annotationSort(sortArray: [])
  317. self?.reloadAnnotation()
  318. }
  319. filterViewController.cancelCallback = { isCancel in
  320. if (isCancel) {
  321. menu.cancelTracking()
  322. }
  323. }
  324. let item = menu.addItem(withTitle: "", action: nil, keyEquivalent: "")
  325. item.target = self
  326. item.representedObject = filterViewController
  327. item.view = filterViewController.view
  328. menu.popUp(positioning: nil, at: CGPointMake(-130, 30), in: button)
  329. }
  330. func fetchNote(for index: Int) -> CPDFAnnotation? {
  331. if self.noteSearchMode { // 搜索模式
  332. return self.noteSearchArray.safe_element(for: index) as? CPDFAnnotation
  333. } else { // 常规模式(非搜索)
  334. let section = self.annotations.safe_element(for: index) as? KMBOTAAnnotationSection
  335. return section?.annotations?.first?.annotation
  336. }
  337. }
  338. @IBAction @objc func sortTypeAction(_ sender: NSMenuItem) {
  339. let item = sender
  340. let tag = item.tag
  341. if (item.state == .on) {
  342. item.state = .off
  343. } else {
  344. item.state = .on
  345. }
  346. if (tag == 0) {
  347. self.noteSortType = .page
  348. self.sortTypeLabel.stringValue = KMLocalizedString("Page", nil)
  349. self.sortTypeBox.toolTip = KMLocalizedString("Page", nil)
  350. } else if (tag == 1) {
  351. self.noteSortType = .time
  352. self.sortTypeLabel.stringValue = KMLocalizedString("Time", nil)
  353. self.sortTypeBox.toolTip = KMLocalizedString("Time", nil)
  354. }
  355. KMDataManager.ud_set(self.noteSortType.rawValue, forKey: Self.Key.noteSortTypeKey)
  356. // self.annotationSort(sortArray: [])
  357. self.reloadAnnotation()
  358. }
  359. }
  360. // MARK: - Note
  361. extension KMLeftSideViewController {
  362. // func loadAnnotationSortData(_ morePredicates: NSArray) {
  363. // var isLink = false
  364. // var typeMutableArr = NSMutableArray()
  365. // if self.allAnnotations.count > 0 {
  366. // for annotation in self.allAnnotations {
  367. // if annotation is CPDFLinkAnnotation || annotation is CPDFTextWidgetAnnotation || annotation is CPDFButtonWidgetAnnotation || annotation is CPDFChoiceWidgetAnnotation {
  368. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeSignature] ||
  369. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeText] ||
  370. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeButton] ||
  371. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeChoice]) {
  372. // isLink = true
  373. // } else {
  374. // if typeMutableArr.contains(annotation.type) == false {
  375. // typeMutableArr.add(annotation.type)
  376. // }
  377. // }
  378. // }
  379. // }
  380. //
  381. // var colorMutableArray = NSMutableArray()
  382. // var typeMutableArray = NSMutableArray()
  383. // var authorMutableArray = NSMutableArray()
  384. // for annotation in self.allAnnotations {
  385. // if annotation is CPDFLinkAnnotation || annotation is CPDFTextWidgetAnnotation || annotation is CPDFButtonWidgetAnnotation || annotation is CPDFChoiceWidgetAnnotation {
  386. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeSignature] ||
  387. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeText] ||
  388. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeButton] ||
  389. //// [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeChoice]) {
  390. // let noteColor = annotation.color ?? .clear
  391. // let noteType = annotation.type ?? ""
  392. // let authorString = annotation.userName() ?? ""
  393. // if (noteColor != nil) {
  394. // if (colorMutableArray.count > 0) {
  395. // if colorMutableArray.contains(noteColor) == false {
  396. // colorMutableArray.add(noteColor)
  397. // }
  398. // } else {
  399. // colorMutableArray.add(noteColor)
  400. // }
  401. // }
  402. // if noteType.isEmpty == false {
  403. // if typeMutableArray.count > 0 {
  404. // if typeMutableArray.contains(noteType) == false {
  405. // typeMutableArray.add(noteType)
  406. // }
  407. // } else {
  408. // typeMutableArray.add(noteType)
  409. // }
  410. // }
  411. // if authorString.isEmpty == false {
  412. // if authorString.count > 0 {
  413. // if authorMutableArray.contains(authorString) == false {
  414. // authorMutableArray.add(authorString)
  415. // }
  416. // } else {
  417. // authorMutableArray.add(authorString)
  418. // }
  419. // }
  420. // } else {
  421. // if typeMutableArr.contains(annotation.type) == false {
  422. // typeMutableArr.add(annotation.type)
  423. // }
  424. // }
  425. // }
  426. //
  427. // let sud = UserDefaults.standard
  428. // var typeArr = NSMutableArray()
  429. //
  430. // if let typeData = KMDataManager.ud_object(forKey: NoteFilterVC.filterSelectTypeKey) as? Data {
  431. // if let data = NSKeyedUnarchiver.unarchiveObject(with: typeData) as? NSArray {
  432. // typeArr = NSMutableArray(array: data)
  433. // }
  434. // }
  435. // var colorArr = NSMutableArray()
  436. // if let colorData = sud.object(forKey: NoteFilterVC.filterSelectColorKey) as? Data {
  437. // if let data = NSKeyedUnarchiver.unarchiveObject(with: colorData) as? NSArray {
  438. // colorArr = NSMutableArray(array: data)
  439. // }
  440. // }
  441. // var authorArr = NSMutableArray()
  442. // if let authorData = sud.object(forKey: NoteFilterVC.filterSelectAuthorKey) as? Data {
  443. // if let data = NSKeyedUnarchiver.unarchiveObject(with: authorData) as? NSArray {
  444. // authorArr = NSMutableArray(array: data)
  445. // }
  446. // }
  447. //
  448. // var temporaryArr1 = NSMutableArray()
  449. // var temporaryArr2 = NSMutableArray()
  450. // var temporaryArr3 = NSMutableArray()
  451. // if (typeArr.count > 0) {
  452. // for type in typeArr {
  453. // if typeMutableArray.contains(type) == false {
  454. // temporaryArr1.add(type)
  455. // }
  456. // }
  457. // }
  458. // if (colorArr.count > 0) {
  459. // for color in colorArr {
  460. // if colorMutableArray.contains(color) == false {
  461. // temporaryArr2.add(color)
  462. // }
  463. // }
  464. // }
  465. // if (authorArr.count > 0) {
  466. // for author in authorArr {
  467. // if authorMutableArray.contains(author) == false {
  468. // temporaryArr3.add(author)
  469. // }
  470. // }
  471. // }
  472. //
  473. // if (temporaryArr1.count > 0) {
  474. // for type in temporaryArr1 {
  475. // typeArr.remove(type)
  476. // }
  477. // }
  478. // if (temporaryArr2.count > 0) {
  479. // for color in temporaryArr2 {
  480. // colorArr.remove(color)
  481. // }
  482. // }
  483. // if (temporaryArr3.count > 0) {
  484. // for author in temporaryArr3 {
  485. // authorArr.remove(author)
  486. // }
  487. // }
  488. //
  489. // var predicateMutableArr = NSMutableArray()
  490. // }
  491. func reloadAnnotation() {
  492. if self.listView != nil {
  493. let filterKey = self.listView?.document?.documentURL.path ?? ""
  494. var typeArr: [Any] = KMBotaTools.noteFilterAnnoTypes(key: filterKey)
  495. var colorArr: [Any] = KMBotaTools.noteFilterColors(key: filterKey)
  496. var authorArr: [Any] = KMBotaTools.noteFilterAuthors(key: filterKey)
  497. if typeArr.count == 0 && colorArr.count == 0 && authorArr.count == 0 {
  498. // self.filtrateButton.image = NSImage(named: "KMImageNameAnnotationsFiltrate")
  499. } else {
  500. // self.filtrateButton.image = NSImage(named: "icon_annotation_screening_select")
  501. }
  502. var dataArray: [KMBOTAAnnotationSection] = []
  503. var annotationArray: [CPDFAnnotation] = []
  504. var allAnnotation: [CPDFAnnotation] = []
  505. for i in 0 ..< self.listView.document.pageCount {
  506. var items: [KMBOTAAnnotationItem] = []
  507. let page = self.listView.document.page(at: i)
  508. var annos: [CPDFAnnotation] = []
  509. // 处理过滤
  510. if typeArr.count == 0 && colorArr.count == 0 && authorArr.count == 0 {
  511. let types = ["Highlight","Underline","Strikeout","Freehand","FreeText","Note","Square","Circle","Line","Stamp","Arrow","Image","Redact","Sign"]
  512. annos = KMOCToolClass.filterAnnotation(annotations: page?.annotations ?? [],types: types) as? [CPDFAnnotation] ?? []
  513. } else {
  514. var filterAnnos: [CPDFAnnotation] = page?.annotations ?? []
  515. if typeArr.count > 0 {
  516. filterAnnos = (KMOCToolClass.filterAnnotation(annotations: filterAnnos, types: typeArr) as? [CPDFAnnotation]) ?? []
  517. }
  518. if (colorArr.count > 0) {
  519. filterAnnos = (KMOCToolClass.filterAnnotation(annotations: filterAnnos,colors: colorArr) as? [CPDFAnnotation]) ?? []
  520. }
  521. if (authorArr.count > 0) {
  522. filterAnnos = (KMOCToolClass.filterAnnotation(annotations: filterAnnos,authors: authorArr) as? [CPDFAnnotation]) ?? []
  523. }
  524. annos = filterAnnos
  525. }
  526. //添加签名注释
  527. for annotation in page?.annotations ?? [] {
  528. if annotation.isKind(of: CPDFSignatureAnnotation.self) {
  529. annos.append(annotation)
  530. }
  531. }
  532. for annotation in annos {
  533. if annotation.annotationShouldDisplay() == false {
  534. annos.removeObject(annotation)
  535. }
  536. }
  537. //转换所有annotation类型
  538. let section = KMBOTAAnnotationSection()
  539. for anno in annos {
  540. let item = KMBOTAAnnotationItem()
  541. item.section = section
  542. item.annotation = anno
  543. item.index = Int(anno.page.pageIndex())
  544. items.append(item)
  545. allAnnotation.append(anno)
  546. }
  547. if items.count != 0 {
  548. section.annotations = items
  549. section.page = page
  550. section.isItemExpanded = true
  551. dataArray.append(section)
  552. }
  553. //添加所有annotation 用于筛选
  554. annotationArray += (page?.annotations ?? [])
  555. }
  556. // 处理排序
  557. if self.noteSortType == .page {
  558. /// 排序(升序)
  559. if self.isAscendSort {
  560. dataArray.sort {
  561. let idx0 = $0.page?.pageIndex() ?? 0
  562. let idx1 = $1.page?.pageIndex() ?? 0
  563. return idx0 <= idx1
  564. }
  565. } else {
  566. dataArray.sort {
  567. let idx0 = $0.page?.pageIndex() ?? 0
  568. let idx1 = $1.page?.pageIndex() ?? 0
  569. return idx0 > idx1
  570. }
  571. }
  572. self.annotations = dataArray
  573. } else if self.noteSortType == .time {
  574. var datas: [KMBOTAAnnotationSection] = []
  575. /// 排序(升序)
  576. if self.isAscendSort {
  577. allAnnotation.sort {
  578. if $0.modificationDate() == nil {
  579. return false
  580. }
  581. if $1.modificationDate() == nil {
  582. return false
  583. }
  584. return $0.modificationDate() <= $1.modificationDate()
  585. }
  586. } else {
  587. allAnnotation.sort {
  588. if $0.modificationDate() == nil {
  589. return false
  590. }
  591. if $1.modificationDate() == nil {
  592. return false
  593. }
  594. return $0.modificationDate() > $1.modificationDate()
  595. }
  596. }
  597. for anno in allAnnotation {
  598. let section = KMBOTAAnnotationSection()
  599. let item = KMBOTAAnnotationItem()
  600. item.section = section
  601. item.annotation = anno
  602. item.index = Int(anno.pageIndex())
  603. section.annotations = [item]
  604. section.page = anno.page
  605. section.isItemExpanded = true
  606. datas.append(section)
  607. }
  608. self.annotations = datas
  609. }
  610. // 转换对象,用于数据显示
  611. self.allAnnotations = annotationArray
  612. // if self.annotations.count < 1 {
  613. // self.filtrateButton.isEnabled = false
  614. // } else {
  615. // self.filtrateButton.isEnabled = true
  616. // }
  617. }
  618. Task { @MainActor in
  619. self.noteOutlineView.reloadData()
  620. }
  621. }
  622. // 搜索 Action
  623. func updateNoteFilterPredicate() {
  624. var stringValue = self.noteSearchField.stringValue
  625. if self.caseInsensitiveNoteSearch { // 忽略大小写
  626. stringValue = stringValue.lowercased()
  627. }
  628. // 清空数据
  629. self.noteSearchArray.removeAll()
  630. if stringValue.isEmpty {
  631. for section in self.annotations {
  632. guard let note = section.annotations?.first?.annotation else {
  633. continue
  634. }
  635. self.noteSearchArray.append(note)
  636. }
  637. } else {
  638. for section in self.annotations {
  639. guard let note = section.annotations?.first?.annotation else {
  640. continue
  641. }
  642. var noteString = KMBOTAAnnotationTool.fetchContentLabelString(annotation: note)
  643. if self.caseInsensitiveNoteSearch {
  644. noteString = noteString.lowercased()
  645. }
  646. if let anno = note as? CPDFMarkupAnnotation {
  647. noteString = anno.markupContent()
  648. }
  649. if noteString.contains(stringValue) {
  650. self.noteSearchArray.append(note)
  651. }
  652. }
  653. }
  654. // 刷新 UI
  655. Task { @MainActor in
  656. self.noteOutlineView.reloadData()
  657. }
  658. }
  659. @objc func selectSelectedNote(_ sender: AnyObject?) {
  660. if self.listView.hideNotes == false {
  661. let selectedNotes = self.selectedNotes()
  662. if selectedNotes.count == 1 {
  663. let annotation = selectedNotes.last!
  664. self.listView.go(to: annotation.bounds, on: annotation.page, animated: true)
  665. // [pdfView scrollAnnotationToVisible:annotation];
  666. // [pdfView setActiveAnnotation:annotation];
  667. self.listView.updateActiveAnnotations([annotation])
  668. self.listView.setNeedsDisplayAnnotationViewForVisiblePages()
  669. // }
  670. }
  671. // NSInteger column = [sender clickedColumn];
  672. // if (column != -1) {
  673. // NSString *colID = [[[sender tableColumns] objectAtIndex:column] identifier];
  674. //
  675. // if ([colID isEqualToString:@"color"]){
  676. // for (PDFAnnotation *annotation in self.pdfView.activeAnnotations) {
  677. // if (![annotation isKindOfClass:[PDFAnnotationChoiceWidget class]] &&
  678. // ![annotation isKindOfClass:[PDFAnnotationButtonWidget class]] &&
  679. // ![annotation isKindOfClass:[PDFAnnotationTextWidget class]]) {
  680. // [[NSColorPanel sharedColorPanel] orderFront:nil];
  681. // break;
  682. // }
  683. //
  684. // }
  685. // }
  686. // }
  687. }
  688. }
  689. func selectedNotes() -> [CPDFAnnotation] {
  690. var selectedNotes: [CPDFAnnotation] = []
  691. let rowIndexes = self.noteOutlineView.selectedRowIndexes
  692. for row in rowIndexes {
  693. let item = self.noteOutlineView.item(atRow: row)
  694. if item is KMBOTAAnnotationItem {
  695. if let anno = (item as! KMBOTAAnnotationItem).annotation {
  696. // if anno.type == nil {
  697. // item = [(SKNoteText *)item note];
  698. // }
  699. if selectedNotes.contains(anno) == false {
  700. selectedNotes.append(anno)
  701. }
  702. }
  703. }
  704. }
  705. return selectedNotes
  706. }
  707. func clearAnnotationFilterData() {
  708. if let _key = self.listView?.document?.documentURL?.path {
  709. let userDefaults = UserDefaults.standard
  710. let typeData = try?NSKeyedArchiver.archivedData(withRootObject: [Any](), requiringSecureCoding: false)
  711. userDefaults.set(typeData, forKey: NoteFilterVC.filterSelectTypeKey + _key)
  712. let colorData = try?NSKeyedArchiver.archivedData(withRootObject: [Any](), requiringSecureCoding: false)
  713. userDefaults.set(colorData, forKey: NoteFilterVC.filterSelectColorKey + _key)
  714. let authorData = try?NSKeyedArchiver.archivedData(withRootObject: [Any](), requiringSecureCoding: false)
  715. userDefaults.set(authorData, forKey: NoteFilterVC.filterSelectAuthorKey + _key)
  716. userDefaults.synchronize()
  717. }
  718. }
  719. }