// // KMBookMarkViewController.swift // PDF Reader Pro // // Created by lxy on 2022/10/10. // import Cocoa import KMComponentLibrary typealias KMBookMarkViewControllerBookMarkDidChange = (_ controller: KMBookMarkViewController, _ bookMarks: [KMBookmarkItem]) -> Void @objc protocol KMBookMarkViewControllerDelegate: NSObjectProtocol { @objc optional func bkControllerAddAction(controller: KMBookMarkViewController, bookmark: CPDFBookmark?, info: [String : Any]?) } extension KMNSearchKey.wholeWords { static let bookmark = "BookmarkSearchWholeWordsKey" } extension KMNSearchKey.caseSensitive { static let bookmark = "BookmarkSearchCaseSensitiveKey" } class KMBookMarkViewController: KMNBotaBaseViewController { @IBOutlet weak var topView: NSView! @IBOutlet weak var addBookButton: NSButton! @IBOutlet weak var titleTextField: NSTextField! @IBOutlet weak var sortButton: NSButton! @IBOutlet var topSeplineView: NSView! @IBOutlet weak var bookTableView: KMBotaTableView! @IBOutlet weak var emptyView: NSView! @IBOutlet weak var bigTipLabel: NSTextField! @IBOutlet weak var tipLabel: NSTextField! private lazy var addButton_: ComponentButton = { let view = ComponentButton() view.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, onlyIcon: true, icon: NSImage(named: "KMBookmarkAdd")) return view }() private var emptyView_: ComponentEmpty = { let view = ComponentEmpty() view.properties = ComponentEmptyProperty(emptyType: .noBookmark, state: .normal, image: NSImage(named: "KMBookmarkEmpty"), text: KMLocalizedString("No Bookmark"), subText: KMLocalizedString("Here is the description.")) return view }() private var groupView: ComponentGroup? = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle()) private var menuGroupView_: ComponentGroup? var dataSource: [KMBookmarkItem] = [] var renameTextField: NSTextField? var renamePDFBook: KMBookmarkItem? var renameCellView: KMBookCellView? weak var document: CPDFDocument? var isLocalEvent: Bool = false //区分外部点击还是内部点击 var selectItems: [KMBookmarkItem] = [] var bookMarkDidChange: KMBookMarkViewControllerBookMarkDidChange? weak var delegate: KMBookMarkViewControllerDelegate? private lazy var handdler_ = KMNBookmarkHanddler() var handdler: KMNBookmarkHanddler { get { return handdler_ } } convenience init() { self.init(nibName: "KMBookMarkViewController", bundle: nil) } override func viewDidLoad() { super.viewDidLoad() handdler.delegate = self titleTextField.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-bold") addBookButton.addSubview(addButton_) addButton_.frame = addBookButton.bounds addButton_.autoresizingMask = [.width, .height] addButton_.setTarget(self, action: #selector(addBookmarkAction)) bookTableView.style = NSTableView.Style.plain bookTableView.allowsMultipleSelection = true bookTableView.doubleAction = #selector(renameBookAction) bookTableView.hasImageToolTips = true bookTableView.botaDelegate = self bookTableView.menuClickedAction = { [unowned self] point in let idxs = self.bookTableView.selectedRowIndexes.count let convertP = self.bookTableView.convert(point, from: nil) let row = self.bookTableView.row(at: convertP) if row == -1 { var viewHeight: CGFloat = 0 let items: [String] = ["Add Bookmark", "All Select", "Delete"] var menuItemArr: [ComponentMenuitemProperty] = [] for value in items { let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: KMLocalizedString(value), identifier: value) if value == "Delete" { properties_Menuitem.keyEquivalent = "⌘ " + String(Unicode.Scalar(NSBackspaceCharacter)!) properties_Menuitem.isDisabled = idxs == 0 } menuItemArr.append(properties_Menuitem) viewHeight += 36 } self.menuGroupView_ = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle()) self.menuGroupView_?.groupDelegate = self self.menuGroupView_?.frame = CGRectMake(0, 0, 180, viewHeight) self.menuGroupView_?.updateGroupInfo(menuItemArr) self.menuGroupView_?.showWithPoint(CGPoint(x: point.x, y: point.y - viewHeight), relativeTo: self.bookTableView) return NSMenu() } return NSMenu() } topView.addSubview(searchButton) searchButton.km_add_size_constraint(size: NSMakeSize(24, 24)) searchButton.km_add_centerY_constraint(constant: 1) searchButton.km_add_trailing_constraint(equalTo: addBookButton, attribute: .leading, constant: -4) searchButton.setTarget(self, action: #selector(_searchAction)) emptyView.addSubview(emptyView_) emptyView_.km_add_top_constraint(constant: 232) emptyView_.km_add_bottom_constraint() emptyView_.km_add_leading_constraint() emptyView_.km_add_trailing_constraint() if let data = headerSearchView { topView.addSubview(data) headerSearchView?.frame = topView.bounds headerSearchView?.autoresizingMask = [.width, .height] } hideHeaderSearch() headerSearchView?.itemClick = { [weak self] idx, params in if idx == 1 { // 显示搜索限制条件 guard let button = params.first as? ComponentButton else { return } self?.showSearchGroupView(sender: button) } else if idx == 2 { // 关闭搜索 self?.hideHeaderSearch() self?.reloadData() } } headerSearchView?.valueDidChange = { [weak self] sender, info in let value = info?[.newKey] as? String ?? "" self?.handdler.searchKey = value self?.reloadData() } self.reloadData() } override func updateUILanguage() { super.updateUILanguage() KMMainThreadExecute { self.titleTextField.stringValue = KMLocalizedString("Bookmarks") } } override func updateUIThemeColor() { super.updateUIThemeColor() KMMainThreadExecute { self.view.wantsLayer = true let color = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-middle") self.view.layer?.backgroundColor = color.cgColor self.topSeplineView.wantsLayer = true self.topSeplineView.layer?.backgroundColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider").cgColor self.titleTextField.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") self.addButton_.properties.icon = NSImage(named: "KMBookmarkAdd") self.addButton_.reloadData() self.searchButton.properties.icon = NSImage(named: "KMImageNameOutlineSearch") self.searchButton.reloadData() } } func reloadData() { var bookMarks: [KMBookmarkItem] = [] for bookmark in handdler.bookmarks() { let item = KMBookmarkItem() item.bookMark = bookmark item.index = UInt(bookmark.pageIndex) item.label = bookmark.label bookMarks.append(item) } self.dataSource = bookMarks self.dataSource.sort(){ guard let index = $0.bookMark?.pageIndex else { return false } guard let otherIndex = $1.bookMark?.pageIndex else { return false } return index < otherIndex } if handdler.isValidSearchMode() { var items: [KMBookmarkItem] = [] for item in dataSource { guard let bookmark = item.bookMark else { continue } if hasContainString(handdler.searchKey, bookmark: bookmark) { items.append(item) } } self.dataSource = items } self.bookTableView.reloadData() self.updateAddBookMarkState() } func addBookMarkAndEdit(newBookMark: KMBookmarkItem) { _ = self.dataSource.contains { item in if handdler.bookmarkIsEqual(bookmark: item.bookMark, otherBookmark: newBookMark.bookMark) { let index = KMOCToolClass.arrayIndexOf(array: self.dataSource, item: item) ?? 0 self.didSelectItem(row: index, event: NSEvent()) self.renameBookWithRow(row: index) return true } return false } } func showSearchGroupView(sender: ComponentButton) { var viewHeight: CGFloat = 8 var menuItemArr: [ComponentMenuitemProperty] = [] let titles = ["Whole Words","Case Sensitive"] for i in titles { let menuI = ComponentMenuitemProperty(text: KMLocalizedString(i)) menuItemArr.append(menuI) viewHeight += 36 } if let info = menuItemArr.first { if KMDataManager.ud_bool(forKey: KMNSearchKey.wholeWords.bookmark) { info.righticon = NSImage(named: "KMNImageNameMenuSelect") } } if let info = menuItemArr.last { if KMDataManager.ud_bool(forKey: KMNSearchKey.caseSensitive.bookmark) { info.righticon = NSImage(named: "KMNImageNameMenuSelect") } } let groupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle()) searchGroupView = groupView groupView?.groupDelegate = self groupView?.frame = CGRectMake(310, 0, 200, viewHeight) groupView?.updateGroupInfo(menuItemArr) var point = sender.convert(sender.frame.origin, to: nil) point.y -= viewHeight groupView?.showWithPoint(point, relativeTo: sender) searchGroupTarget = sender } override func showHeaderSearch() { super.showHeaderSearch() handdler.isSearchMode = true } override func hideHeaderSearch() { super.hideHeaderSearch() handdler.isSearchMode = false } func hasContainString(_ searchString: String, bookmark: CPDFBookmark) -> Bool { var label = bookmark.label ?? "" var searchLabel = searchString if handdler.caseSensitive == false { label = label.lowercased() searchLabel = searchLabel.lowercased() } if label.contains(searchLabel) { if handdler.wholeWords { let words = label.words() return words.contains(searchLabel) } return true } return false } func didSelectItem(row: Int, event: NSEvent?, needJump: Bool = true) { //当选中一个时 if self.bookTableView.selectedRowIndexes.count == 1 || (event != nil && (!event!.modifierFlags.contains(NSEvent.ModifierFlags.command) && !event!.modifierFlags.contains(NSEvent.ModifierFlags.shift))) { self.bookTableView.selectRowIndexes(IndexSet(integer: IndexSet.Element(row)), byExtendingSelection: false) } //原始数据置空 for model in self.selectItems { for (idx, item) in self.dataSource.enumerated() { if item.bookMark != model.bookMark { continue } item.select = false let rowView = self.bookTableView.rowView(atRow: idx, makeIfNecessary: false) as? KMBookMarkTableRowView rowView?.reloadData() } } //获取最新数据 var items: [KMBookmarkItem] = [] for index in self.bookTableView.selectedRowIndexes { if index < self.dataSource.count { let model = self.dataSource[index] model.select = true let rowView = self.bookTableView.rowView(atRow: index, makeIfNecessary: false) as? KMBookMarkTableRowView rowView?.reloadData() items.append(model) } } self.selectItems = items //刷新数据 if needJump { self.updateListViewData() } } func updateListViewData() { let selectedRowIndexes = self.bookTableView.selectedRowIndexes if selectedRowIndexes.count != 1 { return } let idx = selectedRowIndexes.first ?? 0 guard let item = self.dataSource.safe_element(for: idx) as? KMBookmarkItem else { return } handdler.goBookmark(item.bookMark, animated: true) } func cancelSelect() { self.bookTableView.deselectAll(nil) for model in self.selectItems { model.select = false if let index = self.dataSource.firstIndex(of: model) { let rowView = self.bookTableView.rowView(atRow: index, makeIfNecessary: false) as? KMBookMarkTableRowView rowView?.reloadData() } } } func updateAddBookMarkState() { // addButton_.properties.isDisabled = !canAddBorkMark() // addButton_.properties.state = .normal // addButton_.reloadData() } // MARK: - Public Methods public func selectIndex(index: Int) { if index < 0 || index >= self.dataSource.count { return } self.bookTableView.selectRowIndexes(IndexSet(integer: IndexSet.Element(index)), byExtendingSelection: false) self.didSelectItem(row: index, event: NSEvent(), needJump: false) } public func currentPageDidChangedAction(document: CPDFDocument?) { guard let theDocument = document, theDocument.isEqual(to: handdler.document) else { return } if !isLocalEvent { var containSelIndex:Bool = false for (index, value) in self.dataSource.enumerated() { let currentBookmark = handdler.bookmark(for: handdler.currentPageIndex) if handdler.bookmarkIsEqual(bookmark: value.bookMark, otherBookmark: currentBookmark) { containSelIndex = true self.didSelectItem(row: index, event: NSEvent()) break } } if !containSelIndex { self.cancelSelect() } } isLocalEvent = false self.updateAddBookMarkState() } public func canAddBorkMark() -> Bool { return handdler.canAddBorkmark() } public func addCurrentBookmark(callback: ((CPDFBookmark?)->Void)?) { handdler.addCurrentBookmark(callback: callback) } public func removeBookmark(for index: Int) -> Bool { return handdler.removeBookmark(for: index) } public func removeBookmarks(for indexs: IndexSet) -> Bool { return handdler.removeBookmarks(for: indexs) } public func removeAllBookmarks() -> Bool { return handdler.removeAllBookmarks() } public func rename(bookmark: CPDFBookmark, label: String) { handdler.rename(bookmark: bookmark, label: label) } //MARK: - Menu Action @objc func renameBookAction() { if self.bookTableView.selectedRowIndexes.count == 1 { self.renameBookWithRow(row: self.bookTableView.selectedRowIndexes.first!) } else { __NSBeep() } } @IBAction func escButtonAction(_ sender: Any) { self.bookTableView.deselectAll(nil) } @IBAction func addBookmarkAction(_ sender: Any) { addButton_.properties.state = .normal addButton_.reloadData() let currentPageIndex = handdler.currentPageIndex if let data = handdler.bookmark(for: currentPageIndex) { delegate?.bkControllerAddAction?(controller: self, bookmark: data, info: ["result" : false]) return } handdler.addCurrentBookmark(callback: { [unowned self] bookmark in self.delegate?.bkControllerAddAction?(controller: self, bookmark: bookmark, info: nil) self.reloadData() DispatchQueue.main.async { if let bookmark = self.handdler.bookmark(for: Int(currentPageIndex)) { let item = KMBookmarkItem() item.bookMark = bookmark item.label = bookmark.label item.index = UInt(bookmark.pageIndex) self.addBookMarkAndEdit(newBookMark: item) } } }) } @objc func changeLocationAction() { if self.bookTableView.selectedRowIndexes.count == 1 { let item = self.dataSource[self.bookTableView.selectedRowIndexes.first!] let alter = NSAlert() alter.alertStyle = NSAlert.Style.informational alter.messageText = KMLocalizedString("Are you sure you want to set the selected page as the bookmark location?", comment: "") alter.addButton(withTitle: KMLocalizedString("Yes", comment:"")) alter.addButton(withTitle: KMLocalizedString("No", comment:"")) let modlres = alter.runModal() if modlres == .alertFirstButtonReturn { let bookMark = KMBookmarkItem() bookMark.bookMark = item.bookMark bookMark.label = item.label bookMark.index = UInt(handdler.currentPageIndex) self.changeLocation(oldBookMark: item, newBookMark: bookMark) } } else { __NSBeep() } } @objc func deleteBookAction() { if self.bookTableView.selectedRowIndexes.count != 0 { var bookMarks:[KMBookmarkItem] = [] for index in self.bookTableView.selectedRowIndexes { let item = self.dataSource[index] bookMarks.append(item) } self.deleteBookMark(bookMarks: bookMarks) } else { __NSBeep() } } private func renameBookWithRow(row: Int) { self.renamePDFBook = self.dataSource[row] self.renameCellView = self.bookTableView.view(atColumn: 0, row: row, makeIfNecessary: true) as? KMBookCellView self.renameTextField = self.renameCellView?.inputTF self.renameTextField?.delegate = self self.renameTextField?.isEditable = true self.renameTextField?.becomeFirstResponder() } @objc private func _searchAction() { searchButton.properties.state = .normal searchButton.reloadData() showHeaderSearch() } } // MARK: - NSTextFieldDelegate extension KMBookMarkViewController: NSTextFieldDelegate { func controlTextDidEndEditing(_ obj: Notification) { guard let bookmark = renamePDFBook?.bookMark else { return } if (self.renameTextField!.isEqual(obj.object)) { let textField : NSTextField = obj.object as! NSTextField handdler.rename(bookmark: bookmark, label: textField.stringValue) self.renameTextField?.isEditable = false renameCellView?.inputBox.borderWidth = 0 renameCellView?.inputBox.fillColor = .clear } } } // MARK: - NSTableViewDelegate,NSTableViewDataSource extension KMBookMarkViewController : NSTableViewDelegate,NSTableViewDataSource { func numberOfRows(in tableView: NSTableView) -> Int { let count = self.dataSource.count if count == 0 { self.emptyView.isHidden = false } else { self.emptyView.isHidden = true } return count } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { if row < self.dataSource.count { let item: KMBookmarkItem = self.dataSource[row] let cell : KMBookCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMBookCellView"), owner: self) as! KMBookCellView if handdler.isValidSearchMode() { var label = item.bookMark?.label ?? "" let attri = NSMutableAttributedString(string: label, attributes: [ .font : NSFont.SFProTextRegularFont(13), .foregroundColor : KMNColorTools.colorText_1()]) var _searchKey = handdler.searchKey if handdler.caseSensitive == false { label = label.lowercased() _searchKey = _searchKey.lowercased() } let ranges = label.ranges(of: _searchKey) for range in ranges.nsRnage { attri.addAttributes([.font : NSFont.SFProTextBoldFont(13), .foregroundColor: KMNColorTools.colorPrimary_textLight()], range: range) } cell.inputTF.attributedStringValue = attri } else { cell.inputTF.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-regular") cell.inputTF.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/1") cell.inputTF.stringValue = item.bookMark?.label ?? "" cell.bookTitle.stringValue = "\(item.bookMark?.pageIndex ?? 0 + 1)" cell.inputBox.borderWidth = 0 if let data = item.bookMark?.date { cell.dateLabel.stringValue = KMTools.timeString(timeDate: data) } else { cell.dateLabel.stringValue = "" } } cell.textFieldDidEndEditingCallback = { [weak self] textF in self?.renameCellView = cell if let bookmark = item.bookMark { self?.handdler.rename(bookmark: bookmark, label: textF.stringValue) } } return cell } return nil } func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? { let rowView = KMBookMarkTableRowView() rowView.selectionHighlightStyle = .none if row < self.dataSource.count { rowView.model = self.dataSource[row] rowView.menuClickedAction = { [weak self] point in let idxs = self?.bookTableView.selectedRowIndexes.count ?? 0 let tempView = self?.bookTableView.rowView(atRow: row, makeIfNecessary: false) var viewHeight: CGFloat = 0 var items: [String] = ["Rename", "Setting Destination", "Delete"] if idxs > 1 { items = ["Delete"] } var menuItemArr: [ComponentMenuitemProperty] = [] for value in items { let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: KMLocalizedString(value), identifier: value) if value == "Delete" { properties_Menuitem.keyEquivalent = "⌘ " + String(Unicode.Scalar(NSBackspaceCharacter)!) } menuItemArr.append(properties_Menuitem) viewHeight += 36 } if self?.groupView != nil { self?.groupView?.groupDelegate = self self?.groupView?.frame = CGRectMake(0, 0, 180, viewHeight) self?.groupView?.updateGroupInfo(menuItemArr) self?.groupView?.showWithPoint(CGPoint(x: point.x, y: point.y - viewHeight), relativeTo: tempView) } return NSMenu() } rowView.mouseDownAction = { [unowned self] (view, event) in self.didSelectItem(row: row, event: event) } rowView.rightMouseDownAction = { [unowned self] (view, event) in if !KMOCToolClass.arrayContains(array: self.selectItems, annotation: rowView.model) || self.selectItems.count == 1 { self.selectIndex(index: row) } if row < 0 || row >= self.dataSource.count { return } } rowView.hoverCallback = { [unowned self] (mouseEntered, mouseBox) in if let value = ComponentLibrary.shared.getComponentValueFromKey("radius/xs") { let currentValue = value as? CGFloat ?? 0 rowView.box?.cornerRadius = currentValue } self.bookTableView.enumerateAvailableRowViews { view, row in if let data = view as? KMBookMarkTableRowView { data.model.hover = false data.reloadData() } } if mouseEntered { rowView.model.hover = true rowView.reloadData() } else { rowView.model.hover = false rowView.reloadData() } } } return rowView } func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { return 36 } func tableView(_ tableView: NSTableView, shouldSelect tableColumn: NSTableColumn?) -> Bool { self.isLocalEvent = true return true } func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool { self.isLocalEvent = true return true } func tableViewSelectionDidChange(_ notification: Notification) { if self.bookTableView.selectedRow == -1 { self.cancelSelect() } } } // MARK: - KMBotaTableViewDelegate extension KMBookMarkViewController: KMBotaTableViewDelegate { func tableView(_ aTableView: NSTableView, imageContextForRow rowIndex: Int) -> AnyObject? { if aTableView.isEqual(to: self.bookTableView) { let cnt = self.dataSource.count if rowIndex >= cnt { return nil } let model = self.dataSource[rowIndex] return model.bookMark } return nil } } //MARK: - undoRedo extension KMBookMarkViewController { func changeLocation(oldBookMark: KMBookmarkItem, newBookMark: KMBookmarkItem) { document?.removeBookmark(forPageIndex: oldBookMark.index) document?.addBookmark(newBookMark.label, forPageIndex: newBookMark.index) reloadData() } func renamePDFBook(bookmark : KMBookmarkItem! , label:String) { if bookmark.bookMark?.label == label { return } let temp = bookmark.bookMark?.label bookmark.bookMark?.label = label self.reloadData() var indexSet = IndexSet() indexSet.insert(self.bookTableView.row(for: self.renameCellView!)) self.bookTableView.selectRowIndexes(indexSet, byExtendingSelection: false) } func deleteBookMark(bookMarks: [KMBookmarkItem]) { for bookMark in bookMarks { if ((document?.removeBookmark(forPageIndex: bookMark.index)) != nil) { KMPrint("删除标签成功") } } self.reloadData() guard let callBack = bookMarkDidChange else { return } callBack(self, bookMarks) } func addBookMark(bookMarks: [KMBookmarkItem]) { for bookmark in bookMarks { document?.addBookmark(bookmark.label, forPageIndex: UInt(bookmark.index)) } self.reloadData() if bookMarks.count == 1 { DispatchQueue.main.async { if let bookmark = self.handdler.bookmark(for: Int(bookMarks.first!.index)) { let item = KMBookmarkItem() item.bookMark = bookmark item.label = bookmark.label item.index = UInt(bookmark.pageIndex) self.addBookMarkAndEdit(newBookMark: item) } } } guard let callBack = bookMarkDidChange else { return } callBack(self, bookMarks) } @IBAction func undo(_ sender: Any) { handdler.undo() } @IBAction func redo(_ sender: Any) { handdler.redo() } } // MARK: - NSMenuDelegate, NSMenuItemValidation extension KMBookMarkViewController: NSMenuDelegate, NSMenuItemValidation { func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { let action = menuItem.action if (action == #selector(undo)) { return handdler.canUndo() } if (action == #selector(redo)) { return handdler.canRedo() } if action == #selector(renameBookAction) || action == #selector(changeLocationAction) || action == #selector(deleteBookAction) { if self.bookTableView.selectedRowIndexes.count > 1 { if action == #selector(changeLocationAction) { return false } else if action == #selector(renameBookAction) { return false } } else if self.bookTableView.selectedRowIndexes.count == 1 { return true } else { if self.bookTableView.selectedRowIndexes.count == 0 { if action == #selector(changeLocationAction) {} } else { return false } } } return true } } // MARK: - KMNBookmarkHanddlerDelegate extension KMBookMarkViewController: KMNBookmarkHanddlerDelegate { func handdler(_ handdler: KMNBookmarkHanddler, didAdd bookmark: CPDFBookmark?, info: [String : Any]?) { KMMainThreadExecute { self.reloadData() } } func handdler(_ handdler: KMNBookmarkHanddler, didRemove bookmark: CPDFBookmark?, info: [String : Any]?) { KMMainThreadExecute { self.reloadData() } } func handdler(_ handdler: KMNBookmarkHanddler, didRemoveAll info: [String : Any]?) { KMMainThreadExecute { self.reloadData() } } func handdler(_ handdler: KMNBookmarkHanddler, didRename bookmark: CPDFBookmark?, info: [String : Any]?) { KMMainThreadExecute { self.reloadData() } } } // MARK: - ComponentGroupDelegate extension KMBookMarkViewController: ComponentGroupDelegate { func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) { if group == groupView { if let selItem = menuItemProperty { if selItem.text == KMLocalizedString("Delete") { var pageIndexs = IndexSet() for i in bookTableView.selectedRowIndexes { guard let item = dataSource.safe_element(for: i) as? KMBookmarkItem else { continue } if let bookmark = item.bookMark { pageIndexs.insert(bookmark.pageIndex) } } _ = handdler.removeBookmarks(for: pageIndexs) } else if selItem.text == KMLocalizedString("Rename") { renameBookAction() } else if selItem.text == KMLocalizedString("Setting Destination") { changeLocationAction() } } } else if group == searchGroupView { guard let menuI = menuItemProperty else { return } let idx = group?.menuItemArr.firstIndex(of: menuI) if idx == 0 { let key = KMNSearchKey.wholeWords.bookmark let value = KMDataManager.ud_bool(forKey: key) KMDataManager.ud_set(!value, forKey: key) handdler.wholeWords = !value } else if idx == 1 { let key = KMNSearchKey.caseSensitive.bookmark let value = KMDataManager.ud_bool(forKey: key) KMDataManager.ud_set(!value, forKey: key) handdler.caseSensitive = !value } } else if group == menuGroupView_ { guard let menuI = menuItemProperty else { return } let idx = group?.menuItemArr.firstIndex(of: menuI) if idx == 0 { addBookmarkAction(addButton_) } else if idx == 1 { var indexs = IndexSet() for (i, _) in dataSource.enumerated() { indexs.insert(i) } bookTableView.km_safe_selectRowIndexes(indexs, byExtendingSelection: false) for i in indexs { didSelectItem(row: i, event: nil) } } else if idx == 2 { deleteBookAction() } } } func componentGroupDidDismiss(group: ComponentGroup?) { if group == searchGroupView { searchGroupTarget?.properties.state = .normal searchGroupTarget?.reloadData() searchGroupTarget = nil } } }