From 3f37596613d395dac5838a66230c9fd06265d0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Nam=20Long?= Date: Wed, 10 Jun 2026 22:26:09 +0700 Subject: [PATCH] fix(datagrid): Delete key and right-click respect multi-row/cell-range selection D12A: delete(_:) checks gridSelection.affectedRows first, mirroring copy(). D12B: rightMouseDown override skips super when clicking inside existing selection, calls NSMenu.popUpContextMenu directly to preserve the selection set. --- CHANGELOG.md | 2 ++ .../Views/Results/KeyHandlingTableView.swift | 24 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32625cb83..02791051a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Delete key now respects cell-range selection in the data grid, removing all rows covered by the selection instead of ignoring it. +- Right-clicking a row inside a multi-row selection no longer collapses the selection before the context menu appears. - iCloud Sync between the iPhone and Mac apps: the iOS app now uses the Production CloudKit environment, so a development build no longer syncs into a separate database the Mac never reads. - Exports no longer fail mid-table on servers that enforce a statement time limit; the export session disables the limit and restores it afterwards, the same way mysqldump does. (#1633) diff --git a/TablePro/Views/Results/KeyHandlingTableView.swift b/TablePro/Views/Results/KeyHandlingTableView.swift index 0b39899f7..ed6b6d3ec 100644 --- a/TablePro/Views/Results/KeyHandlingTableView.swift +++ b/TablePro/Views/Results/KeyHandlingTableView.swift @@ -222,6 +222,12 @@ final class KeyHandlingTableView: NSTableView { @objc func delete(_ sender: Any?) { guard coordinator?.isEditable == true else { return } + if let controller = gridSelection, !controller.isEmpty { + let rows = controller.selection.affectedRows + guard !rows.isEmpty else { return } + coordinator?.delegate?.dataGridDeleteRows(Set(rows)) + return + } guard !selectedRowIndexes.isEmpty else { return } coordinator?.delegate?.dataGridDeleteRows(Set(selectedRowIndexes)) } @@ -279,7 +285,8 @@ final class KeyHandlingTableView: NSTableView { override func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool { switch item.action { case #selector(delete(_:)), #selector(deleteBackward(_:)): - return coordinator?.isEditable == true && !selectedRowIndexes.isEmpty + let hasGridSelection = gridSelection?.isEmpty == false + return coordinator?.isEditable == true && (hasGridSelection || !selectedRowIndexes.isEmpty) case #selector(copy(_:)): let hasGridSelection = gridSelection?.isEmpty == false return hasGridSelection || !selectedRowIndexes.isEmpty @@ -407,7 +414,7 @@ final class KeyHandlingTableView: NSTableView { private func deleteSelectedRowsIfPossible() { guard coordinator?.isEditable == true else { return } - guard !selectedRowIndexes.isEmpty else { return } + guard gridSelection?.isEmpty == false || !selectedRowIndexes.isEmpty else { return } delete(nil) } @@ -521,6 +528,19 @@ final class KeyHandlingTableView: NSTableView { scrollColumnToVisible(prevColumn) } + override func rightMouseDown(with event: NSEvent) { + let point = convert(event.locationInWindow, from: nil) + let clickedRow = row(at: point) + if clickedRow >= 0, selectedRowIndexes.contains(clickedRow) { + window?.makeFirstResponder(self) + if let menu = menu(for: event) { + NSMenu.popUpContextMenu(menu, with: event, for: self) + } + return + } + super.rightMouseDown(with: event) + } + override func menu(for event: NSEvent) -> NSMenu? { let point = convert(event.locationInWindow, from: nil) let clickedRow = row(at: point)