// // KMLeftSideViewController+Note.swift // PDF Reader Pro // // Created by tangchao on 2023/12/23. // import Foundation extension KMLeftSideViewController.Key { static let noteAscendSortKey = "KMLeftSideViewAscendSortBoolKey" static let noteSortTypeKey = "KMLeftSideViewNoteSortTypeKey" static let noteTableColumn = "KMNoteOutlineViewTableColumnKey" static let noteFilterPage = "kKMNoteFilterAnnotationPageKey" static let noteFilterTime = "kKMNoteFilterAnnotationTimeKey" static let noteFilterAuther = "kKMNoteFilterAnnotationAutherKey" } // MARK: - Menu extension KMLeftSideViewController { func note_initSubViews() { self.noteSearchField.backgroundColor = KMAppearance.Layout.l_1Color() self.noteSearchField.wantsLayer = true self.noteSearchField.layer?.backgroundColor = KMAppearance.Layout.l_1Color().cgColor self.noteSearchField.layer?.borderWidth = 1.0 self.noteMoreButton.target = self self.noteMoreButton.tag = 304 self.noteMoreButton.action = #selector(leftSideViewMoreButtonAction) self.moreButtonLayer = KMButtonLayer() self.noteMoreButton.layer?.addSublayer(self.moreButtonLayer!) self.moreButtonLayer?.frame = CGRectMake(0, 0, CGRectGetWidth(self.noteMoreButton.bounds), CGRectGetHeight(self.noteMoreButton.bounds)) self.noteFilterButton.target = self self.noteFilterButton.action = #selector(noteFilterAction) self.filterButtonLayer = NSView() self.noteFilterButton.addSubview(self.filterButtonLayer!) self.filterButtonLayer?.frame = CGRectMake(14, 2, 8, 8) self.noteDoneButton.action = #selector(leftSideViewDoneButtonAction) self.noteDoneButton.target = self self.noteDoneButton.tag = 311 self.noteDoneButton.isHidden = true self.noteSearchField.delegate = self self.noteSearchField.isHidden = true self.noteSearchField.endEditCallBack = { [unowned self] isEndEdit in if (isEndEdit) { self.noteSearchField.isHidden = true self.noteSearchButton.isHidden = false self.noteTitleLabel.isHidden = false } } self.sortTypeBox.downCallback = { [unowned self] downEntered, mouseBox, _ in if (downEntered) { let menu = NSMenu() let timeItem = menu.addItem(title: KMLocalizedString("Time", nil), action: #selector(sortTypeAction), target: self) timeItem?.representedObject = self timeItem?.tag = 0 let pageItem = menu.addItem(title: KMLocalizedString("Page", nil), action: #selector(sortTypeAction), target: self) pageItem?.representedObject = self timeItem?.tag = 1 if (self.noteSortType == .time) { timeItem?.state = .on pageItem?.state = .off } else if (self.noteSortType == .page) { timeItem?.state = .off pageItem?.state = .on } menu.popUp(positioning: nil, at: CGPointMake(-10, 0), in: self.sortTypeBox) } } self.noteOutlineView.delegate = self self.noteOutlineView.dataSource = self self.noteOutlineView.botaDelegate = self self.noteOutlineView.botaDataSource = self self.noteOutlineView.noteDelegate = self self.noteOutlineView.menu = NSMenu() self.noteOutlineView.menu?.delegate = self self.noteOutlineView.typeSelectHelper = SKTypeSelectHelper(matchOption: .SKSubstringMatch) self.noteOutlineView.registerForDraggedTypes(NSColor.readableTypes(for: NSPasteboard(name: .drag))) self.noteOutlineView.target = self self.noteOutlineView.doubleAction = #selector(selectSelectedNote) } func note_initDefalutValue() { self.noteView.wantsLayer = true self.noteView.layer?.backgroundColor = KMAppearance.Layout.l0Color().cgColor let sud = UserDefaults.standard if let dict = sud.dictionary(forKey: Self.Key.noteTableColumn) { self.noteTypeDict = dict } else { self.noteTypeDict = [Self.Key.noteFilterPage : false, Self.Key.noteFilterTime : false, Self.Key.noteFilterAuther : false] sud.sync_setValue(self.noteTypeDict, forKey: Self.Key.noteTableColumn) } self.caseInsensitiveNoteSearch = sud.bool(forKey: SKCaseInsensitiveNoteSearchKey) self.isAscendSort = KMDataManager.ud_bool(forKey: Self.Key.noteAscendSortKey) self.noteTitleLabel.stringValue = KMLocalizedString("Notes", nil); self.noteTitleLabel.textColor = KMAppearance.Layout.h0Color() self.noteSearchField.layer?.borderColor = KMAppearance.Interactive.a0Color().cgColor self.noteMoreButton.wantsLayer = true self.moreButtonLayer?.layerType = .none self.moreButtonLayer?.isHidden = true self.noteFilterButton.toolTip = KMLocalizedString("Sort", nil) self.noteFilterButton.wantsLayer = true self.filterButtonLayer?.isHidden = true self.filterButtonLayer?.wantsLayer = true self.filterButtonLayer?.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor self.filterButtonLayer?.layer?.cornerRadius = 4.0 if (self.isAscendSort) { self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankReverse) self.noteSortButton.toolTip = KMLocalizedString("ascending sort", nil) } else { self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankPositive) self.noteSortButton.toolTip = KMLocalizedString("descending sort", nil) } self.noteSearchButton.toolTip = KMLocalizedString("Search", nil) self.noteDoneButton.title = KMLocalizedString("Done", nil) self.noteDoneButton.toolTip = KMLocalizedString("Done", nil) self.noteDoneButton.setTitleColor(KMAppearance.Layout.w0Color()) self.noteDoneButton.wantsLayer = true self.noteDoneButton.layer?.backgroundColor = KMAppearance.Interactive.a0Color().cgColor self.noteDoneButton.layer?.cornerRadius = 4.0 self.noteHeaderView.wantsLayer = true self.noteHeaderView.layer?.backgroundColor = KMAppearance.Else.textTagColor().cgColor self.noteHeaderView.layer?.cornerRadius = 1.0 let sortType = KMDataManager.ud_integer(forKey: Self.Key.noteSortTypeKey) if (sortType == 1) { self.noteSortType = KMNoteSortType(rawValue: sortType)! if (self.noteSortType == .time) { self.sortTypeLabel.stringValue = KMLocalizedString("Time", nil) self.sortTypeBox.toolTip = KMLocalizedString("Time", nil) } else if (self.noteSortType == .page) { self.sortTypeLabel.stringValue = KMLocalizedString("Page", nil) self.sortTypeBox.toolTip = KMLocalizedString("Page", nil) } } else { self.noteSortType = .time self.sortTypeLabel.stringValue = KMLocalizedString("Time", nil) } self.sortTypeLabel.textColor = KMAppearance.Layout.h1Color() self.noteOutlineView.backgroundColor = KMAppearance.Layout.l0Color() self.noteOutlineView.autoresizesOutlineColumn = false self.noteOutlineView.indentationPerLevel = 0 } @IBAction func note_expandAllComments(_ sender: AnyObject?) { if (self.foldType == .unfold) { // 已全部展开 return } // 设置全部展开的标识 self.foldType = .unfold // 加载数据 self.loadUnfoldDate(.none) // 刷新UI self.noteOutlineView.reloadData() } @IBAction func note_foldAllComments(_ sender: AnyObject?) { if (self.foldType == .fold) { return } self.foldType = .fold self.loadUnfoldDate(.none) self.noteOutlineView.reloadData() } @IBAction func noteShowNoteAction(_ sender: AnyObject?) { let item = sender as? NSMenuItem let tag = item?.tag ?? 0 if (tag == 100) { } else if (tag == 101) { let isPage = self.noteTypeDict[Self.Key.noteFilterPage] as? Bool ?? false self.noteTypeDict[Self.Key.noteFilterPage] = !isPage } else if (tag == 102) { let isTime = self.noteTypeDict[Self.Key.noteFilterTime] as? Bool ?? false self.noteTypeDict[Self.Key.noteFilterTime] = !isTime } else if (tag == 103) { let isAuther = self.noteTypeDict[Self.Key.noteFilterAuther] as? Bool ?? false self.noteTypeDict[Self.Key.noteFilterAuther] = !isAuther } UserDefaults.standard.sync_setValue(self.noteTypeDict, forKey: Self.Key.noteTableColumn) let selectRow = self.noteOutlineView.selectedRow self.noteOutlineView.reloadData() self.noteOutlineView.selectRowIndexes(IndexSet(integer: selectRow), byExtendingSelection: false) } @objc func exportAnnotationNotes(_ sender: AnyObject?) { let doc = self.view.window?.windowController?.document as? NSDocument doc?.saveTo(sender) } @objc func leftSideEmptyAnnotationClick_DeleteAnnotation(_ sender: AnyObject?) { guard let doc = self.listView.document else { return } Task { 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)]) if response == .alertFirstButtonReturn { var annotations = NSMutableArray() for i in 0 ..< doc.pageCount { let page = self.listView.document.page(at: i) for anno in page?.annotations ?? [] { if anno is CPDFTextWidgetAnnotation || anno is CPDFButtonWidgetAnnotation || anno is CPDFChoiceWidgetAnnotation { continue } // if (@available(macOS 10.13, *)) { // if ([annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeSignature]) { // continue; // } // } // if anno is CPDFInkAnnotation { // continue // } annotations.add(anno) } } for anno in annotations { if let data = anno as? CPDFAnnotation { self.listView.remove(data) } } self.reloadAnnotation() self.noteOutlineView.reloadData() } } } @objc func unfoldNoteAction(_ sender: NSMenuItem) { if sender.state == .on { return } let row = self.noteOutlineView.clickedRow guard let foldNote = self.fetchNote(for: row) else { return } if self.allFoldNotes.contains(foldNote) == false { self.allFoldNotes.append(foldNote) } if self.allFoldNotes.count == self.canFoldNotes.count { self.foldType = .unfold } else { self.foldType = .none } let viewS = self.noteOutlineView.view(atColumn: 0, row: row, makeIfNecessary: true) (viewS as? KMNoteTableViewCell)?.isFold = false } @objc func foldNoteAction(_ sender: NSMenuItem) { // if sender.state == .on { // return // } let row = self.noteOutlineView.clickedRow guard let foldNote = self.fetchNote(for: row) else { return } if self.allFoldNotes.contains(foldNote) == false { self.allFoldNotes.append(foldNote) } if (self.allFoldNotes.count == 0) { self.foldType = .fold } else { self.foldType = .none } let viewS = self.noteOutlineView.view(atColumn: 0, row: row, makeIfNecessary: true) (viewS as? KMNoteTableViewCell)?.isFold = true } @objc func deleteNotes(_ sender: NSMenuItem) { self.outlineView(self.noteOutlineView, deleteItems: sender.representedObject as! [Any]) } @objc func removeAllAnnotations(_ sender: AnyObject?) { self.leftSideEmptyAnnotationClick_DeleteAnnotation(nil) } @objc func editNoteTextFromTable(_ sender: NSMenuItem) { // PDFAnnotation *annotation = [sender representedObject]; guard let annotation = sender.representedObject as? CPDFAnnotation else { return } self.listView.scrollAnnotationToVisible(annotation) // self.listView.activeAnnotation = annotation // [self showNote:annotation]; // SKNoteWindowController *noteController = (SKNoteWindowController *)[self windowControllerForNote:annotation]; // [[noteController window] makeFirstResponder:[noteController textView]]; // [[noteController textView] selectAll:nil]; } @objc func editThisAnnotation(_ sender: AnyObject?) { KMPrint("editThisAnnotation ...") } @objc func editNoteFromTable(_ sender: AnyObject?) { KMPrint("editNoteFromTable ...") } @IBAction func noteSortAction(_ sender: AnyObject?) { if (self.isAscendSort) { self.isAscendSort = false self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankPositive) self.noteSortButton.toolTip = KMLocalizedString("descending sort", nil) } else { self.isAscendSort = true self.noteSortButton.image = NSImage(named: KMImageNameBtnSidebarRankReverse) self.noteSortButton.toolTip = KMLocalizedString("ascending sort", nil) } KMDataManager.ud_set(self.isAscendSort, forKey: Self.Key.noteAscendSortKey) self.annotationSort(sortArray: []) } @IBAction func noteSearchAction(_ sender: NSButton) { self.noteSearchField.isHidden = false self.noteTitleLabel.isHidden = true self.noteSearchButton.isHidden = true self.noteDoneButton.isHidden = false self.noteFilterButton.isHidden = true self.noteMoreButton.isHidden = true self.noteSearchField.becomeFirstResponder() } @IBAction func noteFilterAction(_ sender: AnyObject?) { let button = sender as? NSButton let menu = NSMenu() let filterViewController = KMNoteOutlineFilterViewController() filterViewController.listView = self.listView filterViewController.view.layer?.backgroundColor = .clear var notes = NSMutableArray() // for section in self._annotations { // if section.annotations?.count != 0 { // for item in section.annotations! { // notes.add(item.annotation!) // } // } // } filterViewController.setNotesArray(self.allAnnotations as NSArray) filterViewController.applyFilterCallback = { [weak self] typeArr, colorArr, authorArr, isEmpty in menu.cancelTracking() if (isEmpty) { self?.filterButtonLayer?.isHidden = true } else { self?.filterButtonLayer?.isHidden = false } self?.annotationSort(sortArray: []) } filterViewController.cancelCallback = { isCancel in if (isCancel) { menu.cancelTracking() } } let item = menu.addItem(withTitle: "", action: nil, keyEquivalent: "") item.target = self item.representedObject = filterViewController item.view = filterViewController.view menu.popUp(positioning: nil, at: CGPointMake(-130, 30), in: button) } func fetchNote(for index: Int) -> CPDFAnnotation? { if self.noteSearchMode { // 搜索模式 return self.noteSearchArray.safe_element(for: index) as? CPDFAnnotation } else { // 常规模式(非搜索) let section = self.annotations.safe_element(for: index) as? KMBOTAAnnotationSection return section?.annotations?.first?.annotation } } @IBAction @objc func sortTypeAction(_ sender: NSMenuItem) { let item = sender let tag = item.tag if (item.state == .on) { item.state = .off } else { item.state = .on } if (tag == 0) { self.noteSortType = .page self.sortTypeLabel.stringValue = KMLocalizedString("Page", nil) self.sortTypeBox.toolTip = KMLocalizedString("Page", nil) } else if (tag == 1) { self.noteSortType = .time self.sortTypeLabel.stringValue = KMLocalizedString("Time", nil) self.sortTypeBox.toolTip = KMLocalizedString("Time", nil) } KMDataManager.ud_set(self.noteSortType.rawValue, forKey: Self.Key.noteSortTypeKey) self.annotationSort(sortArray: []) } } // MARK: - Note extension KMLeftSideViewController { func loadAnnotationSortData(_ morePredicates: NSArray) { var isLink = false var typeMutableArr = NSMutableArray() if self.allAnnotations.count > 0 { for annotation in self.allAnnotations { if annotation is CPDFLinkAnnotation || annotation is CPDFTextWidgetAnnotation || annotation is CPDFButtonWidgetAnnotation || annotation is CPDFChoiceWidgetAnnotation { // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeSignature] || // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeText] || // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeButton] || // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeChoice]) { isLink = true } else { if typeMutableArr.contains(annotation.type) == false { typeMutableArr.add(annotation.type) } } } } var colorMutableArray = NSMutableArray() var typeMutableArray = NSMutableArray() var authorMutableArray = NSMutableArray() for annotation in self.allAnnotations { if annotation is CPDFLinkAnnotation || annotation is CPDFTextWidgetAnnotation || annotation is CPDFButtonWidgetAnnotation || annotation is CPDFChoiceWidgetAnnotation { // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeSignature] || // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeText] || // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeButton] || // [annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeChoice]) { let noteColor = annotation.color ?? .clear let noteType = annotation.type ?? "" let authorString = annotation.userName() ?? "" if (noteColor != nil) { if (colorMutableArray.count > 0) { if colorMutableArray.contains(noteColor) == false { colorMutableArray.add(noteColor) } } else { colorMutableArray.add(noteColor) } } if noteType.isEmpty == false { if typeMutableArray.count > 0 { if typeMutableArray.contains(noteType) == false { typeMutableArray.add(noteType) } } else { typeMutableArray.add(noteType) } } if authorString.isEmpty == false { if authorString.count > 0 { if authorMutableArray.contains(authorString) == false { authorMutableArray.add(authorString) } } else { authorMutableArray.add(authorString) } } } else { if typeMutableArr.contains(annotation.type) == false { typeMutableArr.add(annotation.type) } } } let sud = UserDefaults.standard var typeArr = NSMutableArray() if let typeData = KMDataManager.ud_object(forKey: NoteFilterVC.filterSelectTypeKey) as? Data { if let data = NSKeyedUnarchiver.unarchiveObject(with: typeData) as? NSArray { typeArr = NSMutableArray(array: data) } } var colorArr = NSMutableArray() if let colorData = sud.object(forKey: NoteFilterVC.filterSelectColorKey) as? Data { if let data = NSKeyedUnarchiver.unarchiveObject(with: colorData) as? NSArray { colorArr = NSMutableArray(array: data) } } var authorArr = NSMutableArray() if let authorData = sud.object(forKey: NoteFilterVC.filterSelectAuthorKey) as? Data { if let data = NSKeyedUnarchiver.unarchiveObject(with: authorData) as? NSArray { authorArr = NSMutableArray(array: data) } } var temporaryArr1 = NSMutableArray() var temporaryArr2 = NSMutableArray() var temporaryArr3 = NSMutableArray() if (typeArr.count > 0) { for type in typeArr { if typeMutableArray.contains(type) == false { temporaryArr1.add(type) } } } if (colorArr.count > 0) { for color in colorArr { if colorMutableArray.contains(color) == false { temporaryArr2.add(color) } } } if (authorArr.count > 0) { for author in authorArr { if authorMutableArray.contains(author) == false { temporaryArr3.add(author) } } } if (temporaryArr1.count > 0) { for type in temporaryArr1 { typeArr.remove(type) } } if (temporaryArr2.count > 0) { for color in temporaryArr2 { colorArr.remove(color) } } if (temporaryArr3.count > 0) { for author in temporaryArr3 { authorArr.remove(author) } } var predicateMutableArr = NSMutableArray() // predicateMutableArr.add } func reloadAnnotation() { if self.listView != nil { var dataArray: [KMBOTAAnnotationSection] = [] var annotationArray: [CPDFAnnotation] = [] var allAnnotation: [CPDFAnnotation] = [] for i in 0 ..< self.listView.document.pageCount { var annotationItemArray: [KMBOTAAnnotationItem] = [] let page = self.listView.document.page(at: i) let types = ["Highlight","Underline","Strikeout","Freehand","FreeText","Note","Square","Circle","Line","Stamp","Arrow","Image","Redact","Sign"] var pageAnnotations: [CPDFAnnotation] = KMOCToolClass.filterAnnotation(annotations: page!.annotations,types: types) as! [CPDFAnnotation] //添加签名注释 for annotation in page!.annotations { if annotation.isKind(of: CPDFSignatureAnnotation.self) { pageAnnotations.append(annotation) } } for annotation in pageAnnotations { if annotation.annotationShouldDisplay() == false { pageAnnotations.removeObject(annotation) } } //转换所有annotation类型 let section = KMBOTAAnnotationSection() for annotation in pageAnnotations { let item = KMBOTAAnnotationItem() item.section = section item.annotation = annotation item.index = Int(annotation.page.pageIndex()) annotationItemArray.append(item) allAnnotation.append(annotation) } if annotationItemArray.count != 0 { section.annotations = annotationItemArray section.page = page section.isItemExpanded = true dataArray.append(section) } //添加所有annotation 用于筛选 annotationArray += pageAnnotations } if self.noteSortType == .page { /// 根据id进行排序(升序) if self.isAscendSort { dataArray.sort { $0.page!.pageIndex() > $1.page!.pageIndex()} } else { dataArray.sort { $0.page!.pageIndex() <= $1.page!.pageIndex()} } self.annotations = dataArray } else if self.noteSortType == .time { var datas: [KMBOTAAnnotationSection] = [] /// 根据id进行排序(升序) if self.isAscendSort { allAnnotation.sort { if $0.modificationDate() == nil { return false } if $1.modificationDate() == nil { return false } return $0.modificationDate() > $1.modificationDate() } } else { allAnnotation.sort { if $0.modificationDate() == nil { return false } if $1.modificationDate() == nil { return false } return $0.modificationDate() <= $1.modificationDate() } } for anno in allAnnotation { let section = KMBOTAAnnotationSection() let item = KMBOTAAnnotationItem() item.section = section item.annotation = anno item.index = Int(anno.pageIndex()) section.annotations = [item] section.page = anno.page section.isItemExpanded = true datas.append(section) } self.annotations = datas } //转换对象,用于数据显示 // self._annotations = dataArray self.allAnnotations = annotationArray // if self.annotations.count < 1 { // self.filtrateButton.isEnabled = false // } else { // self.filtrateButton.isEnabled = true // } } } func annotationSort(sortArray:[[Any]]) { if self.listView != nil { var typeArr: [Any] = [] var colorArr: [Any] = [] var authorArr: [Any] = [] let sud = UserDefaults.standard let typeData = KMDataManager.ud_object(forKey: NoteFilterVC.filterSelectTypeKey + self.listView.document.documentURL.path) as? Data if typeData != nil { typeArr = NSKeyedUnarchiver.unarchiveObject(with: typeData!) as! [Any] } let colorData = sud.object(forKey: NoteFilterVC.filterSelectColorKey + self.listView.document.documentURL.path) as? Data if colorData != nil { colorArr = NSKeyedUnarchiver.unarchiveObject(with: colorData!) as! [Any] } let authorData = sud.object(forKey: NoteFilterVC.filterSelectAuthorKey + self.listView.document.documentURL.path) as? Data if authorData != nil { authorArr = NSKeyedUnarchiver.unarchiveObject(with: authorData!) as! [Any] } var colorMutableArray = NSMutableArray() var typeMutableArray = NSMutableArray() var authorMutableArray = NSMutableArray() for annotation in self.allAnnotations { if annotation.isKind(of: CPDFInkAnnotation.self) == false && annotation.isKind(of: CPDFTextWidgetAnnotation.self) == false && annotation.isKind(of: CPDFButtonWidgetAnnotation.self) == false && annotation.isKind(of: CPDFChoiceWidgetAnnotation.self) == false // ![annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeSignature] && // ![annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeText] && // ![annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeButton] && // ![annotation.widgetFieldType isEqualToString:PDFAnnotationWidgetSubtypeChoice]) { let noteColor = annotation.color ?? .clear let noteType = annotation.type ?? "" let authorString = annotation.userName() ?? "" if (noteColor != nil) { if (colorMutableArray.count > 0) { if colorMutableArray.contains(noteColor) == false { colorMutableArray.add(noteColor) } } else { colorMutableArray.add(noteColor) } } if noteType.isEmpty == false { if (typeMutableArray.count > 0) { if typeMutableArray.contains(noteType) == false { typeMutableArray.add(noteType) } } else { typeMutableArray.add(noteType) } } if authorString.isEmpty == false { if (authorMutableArray.count > 0) { if authorMutableArray.contains(authorString) == false { authorMutableArray.add(authorString) } } else { authorMutableArray.add(authorString) } } } } // var temporaryArr1 = NSMutableArray() // var temporaryArr2 = NSMutableArray() // var temporaryArr3 = NSMutableArray() // if typeArr.isEmpty == false { // for type in typeArr { // if typeMutableArray.contains(type) == false { // temporaryArr1.add(type) // } // } // } // if colorArr.isEmpty == false { // for color in colorArr { // if colorMutableArray.contains(color) == false { // temporaryArr2.add(type) // } // } // } // if authorArr.isEmpty == false { // for author in authorArr { // if authorMutableArray.contains(author) == false { // temporaryArr3.add(type) // } // } // } // if (temporaryArr1.count > 0) { // for type in temporaryArr1 { // guard let typeS = type as? String else { // continue // } //// [typeArr removeObject:type]; // // var flag = -1 // for (i, data) in typeArr.enumerated() { // if data as! String == typeS { // flag = i // } // } // if flag != -1 { // typeArr.remove(at: flag) // } // } // } // if (temporaryArr2.count > 0) { // for (NSColor *color in temporaryArr2) { // [colorArr removeObject:color]; // } // } // for color in temporaryArr2 { // guard let colorT = color as? NSColor else { // continue // } //// [typeArr removeObject:type]; // // var flag = -1 // for (i, data) in colorArr.enumerated() { // if data as! NSColor == colorT { // flag = i // } // } // if flag != -1 { // colorArr.remove(at: flag) // } // } // if (temporaryArr3.count > 0) { // for (NSColor *author in temporaryArr3) { // [authorArr removeObject:author]; // } // } // for author in temporaryArr3 { // guard let authorS = author as? String else { // continue // } //// [typeArr removeObject:type]; // // var flag = -1 // for (i, data) in authorArr.enumerated() { // if data as! String == authorS { // flag = i // } // } // if flag != -1 { // authorArr.remove(at: flag) // } // } // let data1 = NSKeyedArchiver.archivedData(withRootObject: NSArray(array: typeArr)) // let data2 = NSKeyedArchiver.archivedData(withRootObject: NSArray(array: colorArr)) // let data3 = NSKeyedArchiver.archivedData(withRootObject: NSArray(array: authorArr)) // let sud = UserDefaults.standard // sud.set(data1, forKey: "KMNoteOutlineFilterSelectArray_Type") // sud.set(data2, forKey: "KMNoteOutlineFilterSelectArray_Color") // sud.set(data3, forKey: "KMNoteOutlineFilterSelectArray_Author") // sud.synchronize() if typeArr.count == 0 && colorArr.count == 0 && authorArr.count == 0 { // self.filtrateButton.image = NSImage(named: "KMImageNameAnnotationsFiltrate") self.reloadAnnotation() } else { // self.filtrateButton.image = NSImage(named: "icon_annotation_screening_select") var dataArray: [KMBOTAAnnotationSection] = [] var allAnnotation: [CPDFAnnotation] = [] for i in 0 ..< self.listView.document.pageCount { var annotationItemArray: [KMBOTAAnnotationItem] = [] let page = self.listView.document.page(at: i) if page!.annotations.count > 0 { var filterAnnotations: [CPDFAnnotation] = page!.annotations if typeArr.count > 0 { filterAnnotations = (KMOCToolClass.filterAnnotation(annotations: filterAnnotations, types: typeArr) as! [CPDFAnnotation]) } if (colorArr.count > 0) { filterAnnotations = (KMOCToolClass.filterAnnotation(annotations: filterAnnotations,colors: colorArr) as! [CPDFAnnotation]) } if (authorArr.count > 0) { filterAnnotations = (KMOCToolClass.filterAnnotation(annotations: filterAnnotations,authors: authorArr) as! [CPDFAnnotation]) } let section = KMBOTAAnnotationSection() for annotation in filterAnnotations { let item = KMBOTAAnnotationItem() item.section = section item.annotation = annotation item.index = Int(page!.pageIndex()) annotationItemArray.append(item) allAnnotation.append(annotation) } if annotationItemArray.count != 0 { section.annotations = annotationItemArray section.page = page section.isItemExpanded = true dataArray.append(section) } } } if self.noteSortType == .page { /// 根据id进行排序(升序) if self.isAscendSort { dataArray.sort { if $0.page == nil { return false } if $1.page == nil { return false } return $0.page!.pageIndex() > $1.page!.pageIndex() } } else { dataArray.sort { if $0.page == nil { return false } if $1.page == nil { return false } return $0.page!.pageIndex() <= $1.page!.pageIndex() } } self.annotations = dataArray } else if self.noteSortType == .time { var datas: [KMBOTAAnnotationSection] = [] /// 根据id进行排序(升序) if self.isAscendSort { allAnnotation.sort { if $0.modificationDate() == nil { return false } if $1.modificationDate() == nil { return false } return $0.modificationDate() > $1.modificationDate() } } else { allAnnotation.sort { if $0.modificationDate() == nil { return false } if $1.modificationDate() == nil { return false } return $0.modificationDate() <= $1.modificationDate() } } for anno in allAnnotation { let section = KMBOTAAnnotationSection() let item = KMBOTAAnnotationItem() item.section = section item.annotation = anno item.index = Int(anno.pageIndex()) section.annotations = [item] section.page = anno.page section.isItemExpanded = true datas.append(section) } self.annotations = datas } } Task { @MainActor in self.noteOutlineView.reloadData() } } } func updateNoteFilterPredicate() { //注释筛选 // [rightSideController.noteArrayController setFilterPredicate:[noteTypeSheetController filterPredicateForSearchString:[rightSideController.searchField stringValue] caseInsensitive:mwcFlags.caseInsensitiveNoteSearch]]; var stringValue = self.noteSearchField.stringValue if self.caseInsensitiveNoteSearch { stringValue = stringValue.lowercased() } // NSPredicate *predicate = [noteTypeSheetController filterPredicateForSearchString:[rightSideController.searchField stringValue] caseInsensitive:mwcFlags.caseInsensitiveNoteSearch]; // [self loadAnnotationSortData:[NSArray arrayWithObjects:predicate, nil]]; self.noteSearchArray.removeAll() if stringValue.isEmpty { self.noteSearchArray.removeAll() for section in self.annotations { guard let note = section.annotations?.first?.annotation else { continue } self.noteSearchArray.append(note) } } else { for section in self.annotations { guard let note = section.annotations?.first?.annotation else { continue } var noteString = KMBOTAAnnotationTool.fetchContentLabelString(annotation: note) if self.caseInsensitiveNoteSearch { noteString = noteString.lowercased() } if let anno = note as? CPDFMarkupAnnotation { noteString = anno.markupContent() } if noteString.contains(stringValue) { self.noteSearchArray.append(note) } } } Task { @MainActor in self.noteOutlineView.reloadData() } } @objc func selectSelectedNote(_ sender: AnyObject?) { if self.listView.hideNotes == false { let selectedNotes = self.selectedNotes() if selectedNotes.count == 1 { let annotation = selectedNotes.last! self.listView.go(to: annotation.bounds, on: annotation.page, animated: true) // [pdfView scrollAnnotationToVisible:annotation]; // [pdfView setActiveAnnotation:annotation]; self.listView.updateActiveAnnotations([annotation]) self.listView.setNeedsDisplayAnnotationViewForVisiblePages() // } } // NSInteger column = [sender clickedColumn]; // if (column != -1) { // NSString *colID = [[[sender tableColumns] objectAtIndex:column] identifier]; // // if ([colID isEqualToString:@"color"]){ // for (PDFAnnotation *annotation in self.pdfView.activeAnnotations) { // if (![annotation isKindOfClass:[PDFAnnotationChoiceWidget class]] && // ![annotation isKindOfClass:[PDFAnnotationButtonWidget class]] && // ![annotation isKindOfClass:[PDFAnnotationTextWidget class]]) { // [[NSColorPanel sharedColorPanel] orderFront:nil]; // break; // } // // } // } // } } } func selectedNotes() -> [CPDFAnnotation] { var selectedNotes: [CPDFAnnotation] = [] let rowIndexes = self.noteOutlineView.selectedRowIndexes for row in rowIndexes { let item = self.noteOutlineView.item(atRow: row) if item is KMBOTAAnnotationItem { if let anno = (item as! KMBOTAAnnotationItem).annotation { // if anno.type == nil { // item = [(SKNoteText *)item note]; // } if selectedNotes.contains(anno) == false { selectedNotes.append(anno) } } } } return selectedNotes } func clearAnnotationFilterData() { if let _key = self.listView?.document?.documentURL?.path { let userDefaults = UserDefaults.standard let typeData = try?NSKeyedArchiver.archivedData(withRootObject: [Any](), requiringSecureCoding: false) userDefaults.set(typeData, forKey: NoteFilterVC.filterSelectTypeKey + _key) let colorData = try?NSKeyedArchiver.archivedData(withRootObject: [Any](), requiringSecureCoding: false) userDefaults.set(colorData, forKey: NoteFilterVC.filterSelectColorKey + _key) let authorData = try?NSKeyedArchiver.archivedData(withRootObject: [Any](), requiringSecureCoding: false) userDefaults.set(authorData, forKey: NoteFilterVC.filterSelectAuthorKey + _key) userDefaults.synchronize() } } }