Support for `NSTableView` sections (aka group rows)
helje5 opened this issue · comments
Checklist
- Reviewed the README and documents.
- Searched existing issues for ensure not duplicated.
Description
The NSTableView extension doesn't apply section changes and indices assume a single section.
Motivation and Context
Like the UITableView, NSTableView supports sections (called "group rows" in AppKit). It would be great if they would just work in combination w/ ArraySection's.
Proposed Solution
In NSTableView the sections (group rows) are part of the collection feed to the tableview. E.g.
let source = [
ArraySection(model: "Section 1", elements: ["A", "B", "C"]),
ArraySection(model: "Section 2", elements: ["D", "E", "F"]),
]
Is presented to NSTableView as:
[0] "Section 1"
[1] "A"
[2] "B"
[3] "C"
[4] "Section 2"
[5] "D"
...
It's not obvious that this isn't supported. Maybe AppKitExtension.swift should have
assert(changeset.sectionInserted.isEmpty,
"srz, section updates not yet supported on AppKit!")
...
in the reload
.
Not quite sure about the best way to implement this. The reload
should have all the grouping information necessary. Essentially there would need to be a separate step adjusting the indices to the flat ones, while applying the changes.
Sample TV datasource/delegate on top of ArraySection
extension AppDelegate: NSTableViewDelegate {
func tableView(_ tv: NSTableView, isGroupRow row: Int) -> Bool {
switch test.data[flat: row] {
case .some(.model): return true
default: return false
}
}
func tableView(_ tv: NSTableView, viewFor tc: NSTableColumn?, row: Int)
-> NSView?
{
let label = NSTextField(labelWithString: test.data[flat: row]?.stringValue ?? "-")
return label
}
}
extension AppDelegate: NSTableViewDataSource {
func numberOfRows(in tableView: NSTableView) -> Int {
test.data.flatCount
}
}
final class SectionedTest {
var data = [ ArraySection<String, String> ]()
func applyNewData(_ newValue: [ ArraySection<String, String> ],
on tableView: NSTableView)
{
let changeset = StagedChangeset(source: data, target: newValue)
tableView.reload(using: changeset, with: .effectFade) { newValue in
self.data = newValue
}
}
}
enum Row {
case model(String)
case element(String)
var stringValue: String {
switch self {
case .model(let s), .element(let s): return s
}
}
}
extension Collection where Element == ArraySection<String, String> {
var flatCount : Int {
reduce(0) { $0 + 1 + $1.elements.count }
}
subscript(flat index: Int) -> Row? {
var cursor = 0
for section in self {
if cursor == index { return .model(section.model) }
cursor += 1
if cursor > index { break }
let offset = index - cursor
assert(offset >= 0)
if offset < section.elements.count {
return .element(section.elements[offset])
}
cursor += section.elements.count
}
assertionFailure("index out of range \(index) \(count)")
return nil
}
}
@helje5
The data structure isn't compatible with section and group rows cuz the concepts are different, so I think it won't be able to support NSTableView.