Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions TablePro/Core/ChangeTracking/DataChangeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -369,22 +369,6 @@ final class DataChangeManager: ChangeManaging {
}
}

// MARK: - Undo/Redo Public API

func undoLastChange() -> UndoResult? {
guard let um = undoManagerProvider?(), um.canUndo else { return nil }
lastUndoResult = nil
um.undo()
return lastUndoResult
}

func redoLastChange() -> UndoResult? {
guard let um = undoManagerProvider?(), um.canRedo else { return nil }
lastUndoResult = nil
um.redo()
return lastUndoResult
}

// MARK: - SQL Generation

func generateSQL() throws -> [ParameterizedStatement] {
Expand Down
10 changes: 0 additions & 10 deletions TablePro/Core/Services/Query/RowOperationsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,16 +150,6 @@ final class RowOperationsManager {
)
}

func undoLastChange(tableRows: inout TableRows) -> UndoApplicationResult? {
guard let result = changeManager.undoLastChange() else { return nil }
return applyUndoResult(result, tableRows: &tableRows)
}

func redoLastChange(tableRows: inout TableRows) -> UndoApplicationResult? {
guard let result = changeManager.redoLastChange() else { return nil }
return applyUndoResult(result, tableRows: &tableRows)
}

func applyUndoResult(_ result: UndoResult, tableRows: inout TableRows) -> UndoApplicationResult {
switch result.action {
case .cellEdit(let rowIndex, let columnIndex, _, let previousValue, _, _):
Expand Down
18 changes: 15 additions & 3 deletions TablePro/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -7740,6 +7740,9 @@
},
"Choose a certificate or key file" : {

},
"Choose a fetched model" : {

},
"Choose a folder to watch for .tablepro connection files" : {
"localizations" : {
Expand Down Expand Up @@ -24879,6 +24882,9 @@
}
}
}
},
"Model name" : {

},
"Model not found: %@" : {
"localizations" : {
Expand Down Expand Up @@ -31137,6 +31143,9 @@
}
}
}
},
"Priority %d" : {

},
"Privacy" : {
"localizations" : {
Expand Down Expand Up @@ -35645,9 +35654,6 @@
}
}
}
},
"Select a model" : {

},
"Select a Plugin" : {
"localizations" : {
Expand Down Expand Up @@ -37490,6 +37496,12 @@
}
}
}
},
"Sorted ascending" : {

},
"Sorted descending" : {

},
"Sorting will reload data and discard all unsaved changes." : {
"localizations" : {
Expand Down
50 changes: 50 additions & 0 deletions TablePro/Views/Results/Cells/CellFocusOverlay.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// CellFocusOverlay.swift
// TablePro
//

import AppKit

final class CellFocusOverlay: NSView {
enum Style {
case hidden
case contrastingBorder
}

var style: Style = .hidden {
didSet {
guard oldValue != style else { return }
applyStyle()
}
}

override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
wantsLayer = true
translatesAutoresizingMaskIntoConstraints = false
isHidden = true
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func hitTest(_ point: NSPoint) -> NSView? { nil }

override func viewDidChangeEffectiveAppearance() {
super.viewDidChangeEffectiveAppearance()
if !isHidden { applyStyle() }
}

private func applyStyle() {
switch style {
case .hidden:
isHidden = true
layer?.borderWidth = 0
case .contrastingBorder:
isHidden = false
layer?.borderWidth = 2
layer?.borderColor = NSColor.alternateSelectedControlTextColor.cgColor
}
}
}
44 changes: 22 additions & 22 deletions TablePro/Views/Results/Cells/DataGridBaseCellView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,22 @@ class DataGridBaseCellView: NSTableCellView {
var isFocusedCell: Bool = false {
didSet {
guard oldValue != isFocusedCell else { return }
updateFocusRing()
updateFocusPresentation()
}
}

private lazy var focusOverlay: CellFocusOverlay = {
let overlay = CellFocusOverlay()
addSubview(overlay)
NSLayoutConstraint.activate([
overlay.leadingAnchor.constraint(equalTo: leadingAnchor),
overlay.trailingAnchor.constraint(equalTo: trailingAnchor),
overlay.topAnchor.constraint(equalTo: topAnchor),
overlay.bottomAnchor.constraint(equalTo: bottomAnchor),
])
return overlay
}()

private(set) lazy var backgroundView: NSView = {
let view = NSView()
view.wantsLayer = true
Expand Down Expand Up @@ -189,35 +201,23 @@ class DataGridBaseCellView: NSTableCellView {
override var backgroundStyle: NSView.BackgroundStyle {
didSet {
backgroundView.isHidden = (backgroundStyle == .emphasized) || (changeBackgroundColor == nil)
if isFocusedCell { updateFocusRing() }
updateFocusPresentation()
}
}

override var focusRingMaskBounds: NSRect { bounds }
override var focusRingMaskBounds: NSRect {
backgroundStyle == .emphasized ? .zero : bounds
}

override func drawFocusRingMask() {
guard backgroundStyle != .emphasized else { return }
NSBezierPath(rect: bounds).fill()
}

override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
guard isFocusedCell, backgroundStyle != .emphasized else { return }
NSGraphicsContext.saveGraphicsState()
NSFocusRingPlacement.only.set()
drawFocusRingMask()
NSGraphicsContext.restoreGraphicsState()
}

override func viewDidChangeEffectiveAppearance() {
super.viewDidChangeEffectiveAppearance()
if isFocusedCell {
needsDisplay = true
}
}

private func updateFocusRing() {
focusRingType = isFocusedCell ? .exterior : .none
private func updateFocusPresentation() {
let onEmphasized = backgroundStyle == .emphasized
focusOverlay.style = (isFocusedCell && onEmphasized) ? .contrastingBorder : .hidden
focusRingType = (isFocusedCell && !onEmphasized) ? .exterior : .none
noteFocusRingMaskChanged()
needsDisplay = true
}
}
59 changes: 50 additions & 9 deletions TablePro/Views/Results/Extensions/DataGridView+Selection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,60 @@ extension TableViewCoordinator {
guard !isSyncingSelection else { return }
guard let tableView = notification.object as? NSTableView else { return }

let previousSelection = selectedRowIndices
let newSelection = Set(tableView.selectedRowIndexes.map { $0 })
if newSelection != selectedRowIndices {
if newSelection != previousSelection {
selectedRowIndices = newSelection
}

if let keyTableView = tableView as? KeyHandlingTableView {
if newSelection.isEmpty {
keyTableView.focusedRow = -1
keyTableView.focusedColumn = -1
} else if keyTableView.focusedRow < 0, let firstRow = newSelection.min() {
keyTableView.focusedRow = firstRow
keyTableView.focusedColumn = 1
}
guard let keyTableView = tableView as? KeyHandlingTableView else { return }

let newFocus = resolvedFocus(
previous: previousSelection,
current: newSelection,
existingFocusedRow: keyTableView.focusedRow,
existingFocusedColumn: keyTableView.focusedColumn,
tableView: tableView
)

if keyTableView.focusedRow != newFocus.row {
keyTableView.focusedRow = newFocus.row
}
if keyTableView.focusedColumn != newFocus.column {
keyTableView.focusedColumn = newFocus.column
}
}

private func resolvedFocus(
previous: Set<Int>,
current: Set<Int>,
existingFocusedRow: Int,
existingFocusedColumn: Int,
tableView: NSTableView
) -> (row: Int, column: Int) {
if current.isEmpty {
return (-1, -1)
}

let column = existingFocusedColumn >= 1 ? existingFocusedColumn : 1
let added = current.subtracting(previous)

if let tip = added.max() {
return (tip, column)
}

let removed = previous.subtracting(current)
if let lostTip = removed.max(),
let currentMax = current.max(),
let currentMin = current.min() {
let row = lostTip > currentMax ? currentMax : currentMin
return (row, column)
}

if existingFocusedRow >= 0, current.contains(existingFocusedRow) {
return (existingFocusedRow, column)
}

return (current.min() ?? -1, column)
}
}
Loading
Loading