KMNBotaAnnotationHanddler.swift 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //
  2. // KMNBotaAnnotationHanddler.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by User-Tangchao on 2024/12/6.
  6. //
  7. import Cocoa
  8. @objc enum KMNBotaAnnotationSortType: Int {
  9. case page = 0
  10. case time = 1
  11. }
  12. @objc protocol KMNBotaAnnotationHanddlerDelegate: NSObjectProtocol {
  13. @objc optional func dataDidInit(handdle: KMNBotaAnnotationHanddler, datas: [KMNBotaAnnotationSectionModel]?)
  14. }
  15. @objcMembers class KMNBotaAnnotationHanddler: NSObject {
  16. weak var pdfView: CPDFView?
  17. weak var delegate: KMNBotaAnnotationHanddlerDelegate?
  18. var pdfDocument: CPDFDocument? {
  19. get {
  20. return pdfView?.document
  21. }
  22. }
  23. // 按页面排序
  24. var sortType: KMNBotaAnnotationSortType = .page {
  25. didSet {
  26. reloadAnnottionDatas()
  27. }
  28. }
  29. // 按升序排序
  30. var sortSubType: KMSortMode = .ascending {
  31. didSet {
  32. reloadAnnottionDatas()
  33. }
  34. }
  35. var datas: [KMNBotaAnnotationSectionModel] = [] //实际展示的数据
  36. var allOrgDatas: [KMNBotaAnnotationModel] = [] //所有显示的数据
  37. func defaultallTypes() -> [String] {
  38. return [CPDFAnnotation.kType.highlight,
  39. CPDFAnnotation.kType.underline,
  40. CPDFAnnotation.kType.strikeout,
  41. CPDFAnnotation.kType.squiggly,
  42. CPDFAnnotation.kType.freehand,
  43. CPDFAnnotation.kType.freetext,
  44. CPDFAnnotation.kType.note,
  45. CPDFAnnotation.kType.square,
  46. CPDFAnnotation.kType.circle,
  47. CPDFAnnotation.kType.line,
  48. CPDFAnnotation.kType.arrow,
  49. CPDFAnnotation.kType.stamp,
  50. CPDFAnnotation.kType.image,
  51. CPDFAnnotation.kType.sign,
  52. CPDFAnnotation.kType.redact,
  53. CPDFAnnotation.kType.polyline,
  54. CPDFAnnotation.kType.polygon]
  55. }
  56. func reloadOrgAllAnnottionDatas(){
  57. allOrgDatas = []
  58. enumerateAllPages { page, stop in
  59. // 根据注释 Type 过滤
  60. let filterNotes = getFilterNotes(types: defaultallTypes(), for: page)
  61. if filterNotes.isEmpty {
  62. return
  63. }
  64. for note in filterNotes {
  65. if note.annotationShouldDisplay() == false { // 注释已隐藏
  66. continue
  67. }
  68. let model = KMNBotaAnnotationModel()
  69. model.annotation = note
  70. allOrgDatas.append(model)
  71. }
  72. }
  73. }
  74. func reloadAnnottionDatas(){
  75. var showDatas:[KMNBotaAnnotationSectionModel] = []
  76. if sortType == .page {
  77. var sortedOrgDatas:[KMNBotaAnnotationModel] = []
  78. if sortSubType == .ascending {
  79. sortedOrgDatas = allOrgDatas.sorted { $0.annotation?.pageIndex() ?? 0 < $1.annotation?.pageIndex() ?? 0 }
  80. } else {
  81. sortedOrgDatas = allOrgDatas.sorted { $0.annotation?.pageIndex() ?? 0 > $1.annotation?.pageIndex() ?? 0 }
  82. }
  83. for annotationModel in sortedOrgDatas {
  84. var isNeedAdd = true
  85. for sectionModel in showDatas {
  86. if let item = sectionModel.items.first {
  87. if(item.annotation?.pageIndex() == annotationModel.annotation?.pageIndex()) {
  88. sectionModel.items.append(annotationModel)
  89. isNeedAdd = false
  90. break
  91. }
  92. }
  93. }
  94. if isNeedAdd == false {
  95. let sectionModel = KMNBotaAnnotationSectionModel()
  96. sectionModel.items.append(annotationModel)
  97. showDatas.append(sectionModel)
  98. }
  99. }
  100. } else if sortType == .time {
  101. var sortedOrgDatas:[KMNBotaAnnotationModel] = []
  102. if sortSubType == .ascending {
  103. let sortedOrgDatas = allOrgDatas.sorted { $0.annotationDate.timeIntervalSince1970 < $1.annotationDate.timeIntervalSince1970 }
  104. } else {
  105. let sortedOrgDatas = allOrgDatas.sorted { $0.annotationDate.timeIntervalSince1970 > $1.annotationDate.timeIntervalSince1970 }
  106. }
  107. for annotationModel in sortedOrgDatas {
  108. var isNeedAdd = true
  109. for sectionModel in showDatas {
  110. if let item = sectionModel.items.first {
  111. let theDate = item.annotation?.modificationDate()
  112. let newDate = annotationModel.annotation?.modificationDate()
  113. if (theDate != nil) {
  114. if theDate!.isSameDay(other: newDate) {
  115. sectionModel.items.append(annotationModel)
  116. isNeedAdd = false
  117. break
  118. }
  119. }
  120. }
  121. }
  122. if isNeedAdd == true {
  123. let sectionModel = KMNBotaAnnotationSectionModel()
  124. sectionModel.items.append(annotationModel)
  125. showDatas.append(sectionModel)
  126. }
  127. }
  128. }
  129. datas = showDatas
  130. delegate?.dataDidInit?(handdle: self, datas: datas)
  131. }
  132. // 获取 Page 的 注释列表 【根据 Types】
  133. func getFilterNotes(types: [String], for page: CPDFPage) -> [CPDFAnnotation] {
  134. let notes = page.annotations ?? []
  135. let filterNotes = Self.filterAnnotation(annotations: notes, types: types)
  136. return filterNotes as? [CPDFAnnotation] ?? []
  137. }
  138. // 遍历 所有 Section 试图模型 【二分法 遍历】
  139. /*
  140. orderedAscending: 左操作数小于右操作数
  141. orderedDescending: 左操作数大于右操作数
  142. orderedSame: 左右操作数相等
  143. */
  144. func enumeratedAllSectionViewModel(callback: ((_ viewModel: KMNBotaAnnotationSectionModel?, _ stop: inout Bool, _ result: inout ComparisonResult)->Void)) {
  145. var lowerBound = 0
  146. var upperBound = datas.count
  147. var stop = false
  148. var result: ComparisonResult = .orderedSame
  149. while lowerBound < upperBound {
  150. let midIndex = lowerBound + (upperBound - lowerBound) / 2
  151. callback(datas[midIndex], &stop, &result)
  152. if stop || result == .orderedSame { // 找到
  153. break
  154. }
  155. if result == .orderedAscending { // 左操作数小于右操作数 则在 下半区查找
  156. lowerBound = midIndex + 1
  157. } else {
  158. upperBound = midIndex
  159. }
  160. }
  161. return callback(nil, &stop, &result)
  162. }
  163. // 获取所有 Page
  164. func enumerateAllPages(callback: ((_ page: CPDFPage, _ stop: inout Bool)->Void)) {
  165. let count = pdfDocument?.pageCount ?? 0
  166. for i in 0 ..< count {
  167. guard let page = pdfDocument?.page(at: i) else {
  168. continue
  169. }
  170. var stop = false
  171. callback(page, &stop)
  172. if stop {
  173. break
  174. }
  175. }
  176. }
  177. class func filterAnnotation(annotations: [Any], types: [Any]) -> [Any] {
  178. let array = annotations
  179. let leftExpression = NSExpression(forKeyPath: "type")
  180. let rightExpression = NSExpression(forConstantValue: types)
  181. let predicate = NSComparisonPredicate(
  182. leftExpression: leftExpression,
  183. rightExpression: rightExpression,
  184. modifier: .direct,
  185. type: .in,
  186. options: .diacriticInsensitive
  187. )
  188. return (array as NSArray).filtered(using: predicate)
  189. }
  190. }