123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- //
- // KMTableView.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2023/11/16.
- //
- import Cocoa
- @objc protocol KMBotaTableViewDelegate: NSTableViewDelegate {
- @objc optional func tableView(_ aTableView: NSTableView, deleteRowsWithIndexes rowIndexes: IndexSet)
- @objc optional func tableView(_ aTableView: NSTableView, canDeleteRowsWithIndexes rowIndexes: IndexSet) -> Bool
-
- @objc optional func tableView(_ aTableView: NSTableView, copyRowsWithIndexes rowIndexes: IndexSet)
- @objc optional func tableView(_ aTableView: NSTableView, canCopyRowsWithIndexes rowIndexes: IndexSet) -> Bool
-
- @objc optional func tableView(_ aTableView: NSTableView, pasteFromPasteboard pboard: NSPasteboard)
- @objc optional func tableView(_ aTableView: NSTableView, canPasteFromPasteboard pboard: NSPasteboard) -> Bool
-
- @objc optional func tableViewMoveLeft(_ aTableView: NSTableView)
- @objc optional func tableViewMoveRight(_ aTableView: NSTableView)
-
- @objc optional func tableViewMoveUp(_ aTableView: NSTableView)
- @objc optional func tableViewMoveDown(_ aTableView: NSTableView)
-
- @objc optional func tableView(_ aTableView: NSTableView, imageContextForRow rowIndex: Int) -> AnyObject?
-
- @objc optional func tableView(_ aTableView: NSTableView, typeSelectHelperSelectionStrings aTypeSelectHelper: SKTypeSelectHelper) -> NSArray
- @objc optional func tableView(_ aTableView: NSTableView, typeSelectHelper aTypeSelectHelper: SKTypeSelectHelper, didFailToFindMatchForSearchString searchString: String)
- @objc optional func tableView(_ aTableView: NSTableView, typeSelectHelper aTypeSelectHelper: SKTypeSelectHelper, updateSearchString searchString: String)
- }
- class KMBotaTableView: NSTableView {
- var kmTrackingAreas: NSMutableSet?
- var supportsQuickLook = false
- var typeSelectHelper: SKTypeSelectHelper?
- weak var botaDelegate: KMBotaTableViewDelegate? {
- didSet {
- self._rebuildTrackingAreas()
- }
- }
-
- var hasImageToolTips: Bool {
- get {
- return self.kmTrackingAreas != nil
- }
- set {
- if self.kmTrackingAreas == nil && newValue {
- self.kmTrackingAreas = NSMutableSet()
- if self.window != nil {
- self._rebuildTrackingAreas()
- }
- } else if self.kmTrackingAreas != nil && newValue == false {
- if self.window != nil {
- self._removeTrackingAreas()
- }
- }
- }
- }
-
- func setTypeSelectHelper(_ newTypeSelectHelper: SKTypeSelectHelper) {
- if typeSelectHelper != newTypeSelectHelper {
- if self.isEqual(to: self.typeSelectHelper?.delegate) {
- typeSelectHelper?.delegate = nil
- }
- typeSelectHelper = newTypeSelectHelper
- typeSelectHelper?.delegate = self
- }
- }
-
- override func draw(_ dirtyRect: NSRect) {
- super.draw(dirtyRect)
- // Drawing code here.
- }
-
- override func reloadData() {
- super.reloadData()
-
- self._rebuildTrackingAreas()
- self.typeSelectHelper?.rebuildTypeSelectSearchCache()
- }
-
- // MARK: - Tracking
-
- override func updateTrackingAreas() {
- super.updateTrackingAreas()
-
- self._rebuildTrackingAreas()
- }
-
- override func noteNumberOfRowsChanged() {
- super.noteNumberOfRowsChanged()
-
- self._rebuildTrackingAreas()
- }
-
- override func mouseEntered(with event: NSEvent) {
- if (self.kmTrackingAreas == nil) {
- return
- }
-
- let userInfo = event.trackingArea?.userInfo as? [String : Any]
- let row = userInfo?["row"] as? Int
- if row != nil {
- let context = self.botaDelegate?.tableView?(self, imageContextForRow: row!)
- if context is KMImageToolTipContext {
- KMImageToolTipWindow.shared.showForImageContext(context as! KMImageToolTipContext, at: .zero)
- }
- }
- }
-
- override func mouseExited(with event: NSEvent) {
- if (self.kmTrackingAreas == nil) {
- return
- }
-
- let userInfo = event.trackingArea?.userInfo as? [String : Any]
- let row = userInfo?["row"] as? Int
- if row != nil {
- KMImageToolTipWindow.shared.fadeOut()
- }
- }
-
- func scrollToBeginningOfDocument(_ sender: AnyObject?) {
- if self.numberOfRows > 0 {
- self.scrollRowToVisible(0)
- }
- }
-
- func scrollToEndOfDocument(_ sender: AnyObject?) {
- if self.numberOfRows > 0 {
- self.scrollRowToVisible(self.numberOfRows-1)
- }
- }
-
- func moveLeft(_ sender: AnyObject?) {
- self.botaDelegate?.tableViewMoveLeft?(self)
- }
- func moveRight(_ sender: AnyObject?) {
- self.botaDelegate?.tableViewMoveRight?(self)
- }
-
- func moveUp(_ sender: AnyObject?) {
- self.botaDelegate?.tableViewMoveUp?(self)
- }
- func moveDown(_ sender: AnyObject?) {
- self.botaDelegate?.tableViewMoveDown?(self)
- }
-
- func canDelete() -> Bool {
- let indexes = self.selectedRowIndexes
- if indexes.isEmpty {
- return false
- }
-
- return self.botaDelegate?.tableView?(self, canDeleteRowsWithIndexes: indexes) ?? false
- }
-
- @objc func delete(_ sender: AnyObject?) {
- if self.canDelete() {
- self.botaDelegate?.tableView?(self, deleteRowsWithIndexes: self.selectedRowIndexes)
- }
- }
-
- func canCopy() -> Bool {
- let indexes = self.selectedRowIndexes
- if indexes.isEmpty {
- return false
- }
-
- return self.botaDelegate?.tableView?(self, canCopyRowsWithIndexes: indexes) ?? false
- }
-
- @objc func copy(_ sender: AnyObject?) {
- if self.canCopy() {
- self.botaDelegate?.tableView?(self, copyRowsWithIndexes: self.selectedRowIndexes)
- }
- }
-
- func canPaste() -> Bool {
- return self.botaDelegate?.tableView?(self, canPasteFromPasteboard: NSPasteboard.general) ?? false
- }
-
- @objc func paste(_ sender: AnyObject?) {
- if self.canPaste() {
- self.botaDelegate?.tableView?(self, pasteFromPasteboard: NSPasteboard.general)
- }
- }
-
- override func keyDown(with event: NSEvent) {
- let eventChar = event.firstCharacter()
- let modifierFlags = event.deviceIndependentModifierFlags()
- if ((eventChar == NSNewlineCharacter || eventChar == NSEnterCharacter || eventChar == NSCarriageReturnCharacter) && modifierFlags == 0) {
- if self.doubleAction == nil || self.sendAction(self.doubleAction, to: self.target) == false {
- NSSound.beep()
- }
- } else if ((eventChar == NSDeleteCharacter || eventChar == NSDeleteFunctionKey) && modifierFlags == 0 && self.canDelete()) {
- self.delete(self)
- } else if ((eventChar == SKSpaceCharacter) && modifierFlags == 0) {
- if (self.supportsQuickLook == false) {
- self.enclosingScrollView?.pageDown(nil)
- } else if QLPreviewPanel.sharedPreviewPanelExists() && QLPreviewPanel.shared().isVisible {
- QLPreviewPanel.shared().orderOut(nil)
- } else {
- QLPreviewPanel.shared().makeKeyAndOrderFront(nil)
- }
- } else if ((eventChar == SKSpaceCharacter) && modifierFlags == NSEvent.ModifierFlags.shift.rawValue) {
- if (self.supportsQuickLook == false) {
- self.enclosingScrollView?.pageUp(nil)
- }
- }
- // else if (eventChar == NSHomeFunctionKey && (modifierFlags & ~NSFunctionKeyMask) == 0) {
- // [self scrollToBeginningOfDocument:nil];
- // } else if (eventChar == NSEndFunctionKey && (modifierFlags & ~NSFunctionKeyMask) == 0) {
- // [self scrollToEndOfDocument:nil];
- // }
- else if (eventChar == NSLeftArrowFunctionKey && modifierFlags == 0) {
- self.moveLeft(nil)
- } else if (eventChar == NSRightArrowFunctionKey && modifierFlags == 0) {
- self.moveRight(nil)
- } else if eventChar == NSUpArrowFunctionKey {
- self.moveUp(nil)
- } else if eventChar == NSDownArrowFunctionKey {
- self.moveDown(nil)
- }
- // else if ([typeSelectHelper handleEvent:theEvent] == NO) {
- // [super keyDown:theEvent];
- // }
- }
-
- override var font: NSFont? {
- get {
- for tc in self.tableColumns {
- if let cell = tc.dataCell as? NSCell {
- if cell.type == .textCellType {
- return cell.font
- }
- }
- }
- return nil
- }
- set {
- for tc in self.tableColumns {
- if let cell = tc.dataCell as? NSCell {
- if cell.type == .textCellType {
- cell.font = newValue
- }
- }
- }
-
- var rowHeight = font?.defaultViewLineHeight() ?? 34
- if self.selectionHighlightStyle == .sourceList {
- rowHeight += 2.0
- }
- self.rowHeight = rowHeight
- self.noteHeightOfRows(withIndexesChanged: IndexSet(0..<self.numberOfRows))
- }
- }
-
- override func dragImageForRows(with dragRows: IndexSet, tableColumns: [NSTableColumn], event dragEvent: NSEvent, offset dragImageOffset: NSPointPointer) -> NSImage {
- return super.dragImageForRows(with: dragRows, tableColumns: tableColumns[0..<1].shuffled(), event: dragEvent, offset: dragImageOffset)
- }
- }
- // MARK: - Private Methods
- extension KMBotaTableView {
- private func _rebuildTrackingAreas() {
- if self.kmTrackingAreas == nil {
- return
- }
-
- let context = self.botaDelegate?.tableView?(self, imageContextForRow: 0)
- if context == nil {
- return
- }
-
- self._removeTrackingAreas()
- if self.window != nil {
- let visibleRect = self.visibleRect
- let rowRange = self.rows(in: visibleRect)
- for i in rowRange.location ..< NSMaxRange(rowRange) {
- self._addTrackingAreaForRow(Int(i))
- }
- }
- }
-
- private func _removeTrackingAreas() {
- if (self.kmTrackingAreas == nil) {
- return
- }
-
- for area in self.kmTrackingAreas! {
- self.removeTrackingArea(area as! NSTrackingArea)
- }
- self.kmTrackingAreas?.removeAllObjects()
- }
-
- private func _addTrackingAreaForRow(_ row: Int) {
- if (self.kmTrackingAreas == nil) {
- return
- }
- let userInfo = ["row" : row]
- var rect = self.rect(ofRow: row)
- rect.size.height -= 1
- let area = NSTrackingArea(rect: rect, options: [.mouseEnteredAndExited, .activeInActiveApp], owner: self, userInfo: userInfo)
- self.addTrackingArea(area)
- self.kmTrackingAreas?.add(area)
- }
- }
- // MARK: - NSMenuItemValidation
- extension KMBotaTableView: NSMenuItemValidation {
- func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
- if menuItem.action == #selector(delete) {
- return self.canDelete()
- } else if menuItem.action == KMSelectorCopy {
- return self.canCopy()
- } else if menuItem.action == #selector(paste) {
- return self.canPaste()
- } else if menuItem.action == #selector(selectAll) {
- return self.allowsMultipleSelection
- } else if menuItem.action == #selector(deselectAll) {
- return self.allowsEmptySelection
- }
- // else if ([[SKTableView superclass] instancesRespondToSelector:@selector(validateMenuItem:)])
- // return [super validateMenuItem:menuItem];
-
- return true
- }
- }
- // MARK: - SKTypeSelectHelperDelegate
- extension KMBotaTableView: SKTypeSelectHelperDelegate {
- func typeSelectHelperSelectionStrings(_ typeSelectHelper: SKTypeSelectHelper) -> NSArray {
- return self.botaDelegate?.tableView?(self, typeSelectHelperSelectionStrings: typeSelectHelper) ?? NSArray()
- }
-
- func typeSelectHelperCurrentlySelectedIndex(_ typeSelectHelper: SKTypeSelectHelper) -> Int {
- return self.selectedRowIndexes.last ?? NSNotFound
- }
-
- func typeSelectHelper(_ typeSelectHelper: SKTypeSelectHelper, selectItemAtIndex itemIndex: Int) {
- self.selectRowIndexes(NSIndexSet(index: itemIndex) as IndexSet, byExtendingSelection: false)
- self.scrollRowToVisible(itemIndex)
- }
-
- func typeSelectHelper(_ typeSelectHelper: SKTypeSelectHelper, didFailToFindMatchForSearchString searchString: String) {
- self.botaDelegate?.tableView?(self, typeSelectHelper: typeSelectHelper, didFailToFindMatchForSearchString: searchString)
- }
-
- func typeSelectHelper(_ typeSelectHelper: SKTypeSelectHelper, updateSearchString searchString: String) {
- self.botaDelegate?.tableView?(self, typeSelectHelper: typeSelectHelper, updateSearchString: searchString)
- }
- }
|