// // KMNBookmarkHanddler.swift // PDF Reader Pro // // Created by User-Tangchao on 2024/11/8. // import Cocoa @objc protocol KMNBookmarkHanddlerDelegate: NSObjectProtocol { @objc optional func handdler(_ handdler: KMNBookmarkHanddler, didAdd bookmark: CPDFBookmark?, info: [String : Any]?) @objc optional func handdler(_ handdler: KMNBookmarkHanddler, didRemove bookmark: CPDFBookmark?, info: [String : Any]?) @objc optional func handdler(_ handdler: KMNBookmarkHanddler, didRemoveAll info: [String : Any]?) @objc optional func handdler(_ handdler: KMNBookmarkHanddler, didRename bookmark: CPDFBookmark?, info: [String : Any]?) } class KMNBookmarkHanddler: NSObject { weak var pdfView: CPDFView? weak var delegate: KMNBookmarkHanddlerDelegate? var isSearchMode = false var wholeWords = false var caseSensitive = false var searchKey = "" func isValidSearchMode() -> Bool { if isSearchMode == false { return false } if searchKey.isEmpty { return false } return true } var document: CPDFDocument? { get { return pdfView?.document } } var currentPageIndex: Int { get { return pdfView?.currentPageIndex ?? 0 } } func canUndo() -> Bool { return pdfView?.undoManager?.canUndo ?? false } func canRedo() -> Bool { return pdfView?.undoManager?.canRedo ?? false } func undo() { if canUndo() { pdfView?.undoManager?.undo() } } func redo() { if canRedo() { pdfView?.undoManager?.redo() } } func addCurrentBookmark(callback: ((CPDFBookmark?)->Void)?) { let currentPageIndex = self.currentPageIndex if let _ = bookmark(for: currentPageIndex) { } else { let label = "\(NSLocalizedString("Page", comment:"")) \(currentPageIndex + 1)" let bookMark = KMBookMarkItem() bookMark.label = label bookMark.index = UInt(currentPageIndex) self._undo_add(label: label, index: currentPageIndex) callback?(self.bookmark(for: currentPageIndex)) } } func removeBookmark(for index: Int) -> Bool { guard let bk = self.bookmark(for: index) else { return false } self._undo_remove(label: bk.label, index: bk.pageIndex) return true } func removeBookmarks(for indexs: IndexSet) -> Bool { var bks: [CPDFBookmark] = [] for i in indexs { if let bk = self.bookmark(for: i) { bks.append(bk) } } if bks.isEmpty { return false } _undo_removeAll(bookmarks: bks) return true } func removeAllBookmarks() -> Bool { guard let bks = document?.bookmarks(), bks.isEmpty == false else { return false } _undo_removeAll(bookmarks: bks) return true } @objc func rename(bookmark: CPDFBookmark, label: String) { guard let theLabel = bookmark.label, theLabel != label else { return } _undo_rename(bookmark: bookmark, label: label) } func bookmark(for pageIndex: Int) -> CPDFBookmark? { return document?.bookmark(forPageIndex: UInt(pageIndex)) } // MARK: - Private Methods // MARK: - Undo & Redo @objc private func _undo_remove(label: String, index: Int) { let bookmark = self.bookmark(for: index) document?.removeBookmark(forPageIndex: UInt(index)) pdfView?.setNeedsDisplayForVisiblePages() delegate?.handdler?(self, didRemove: bookmark, info: nil) (pdfView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject)._undo_add(label: label, index: index) } @objc private func _undo_add(label: String, index: Int) { document?.addBookmark(label, forPageIndex: UInt(index)) pdfView?.setNeedsDisplayForVisiblePages() delegate?.handdler?(self, didAdd: self.bookmark(for: index), info: nil) (pdfView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject)._undo_remove(label: label, index: index) } @objc private func _undo_removeAll(bookmarks: [CPDFBookmark]) { for bookmark in bookmarks { document?.removeBookmark(forPageIndex: UInt(bookmark.pageIndex)) } pdfView?.setNeedsDisplayForVisiblePages() delegate?.handdler?(self, didRemoveAll: nil) (pdfView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject)._undo_removeAll_back(bookmarks: bookmarks) } @objc private func _undo_removeAll_back(bookmarks: [CPDFBookmark]) { for bookmark in bookmarks { document?.addBookmark(bookmark.label, forPageIndex: UInt(bookmark.pageIndex)) } pdfView?.setNeedsDisplayForVisiblePages() delegate?.handdler?(self, didRemoveAll: nil) (pdfView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject)._undo_removeAll(bookmarks: bookmarks) } @objc private func _undo_rename(bookmark: CPDFBookmark, label: String) { let theLabel = bookmark.label ?? "" bookmark.label = label delegate?.handdler?(self, didRename: bookmark, info: nil) (pdfView?.undoManager?.prepare(withInvocationTarget: self) as AnyObject)._undo_rename(bookmark: bookmark, label: theLabel) } }