I'm working with an application were I'm wanting to combine all cells in an NSTableView to act as a section header for rows below it. One solution I'm working with is to use - (BOOL)tableView:isGroupRow: which works somewhat, but unfortunately the formatting that I am using on the NSTextField gets clobbered when using isGroupRow, the text should be white and the bold appears regardless of whether I set it or not.
In the sample code if you uncomment out the line // return false
in tableView(_ tableView: NSTableView, isGroupRow row: Int)
you'll see the correct formatting working fine (except that of course the field shows up twice since it's not being converted to a group row
The solution takes several steps and a full sample project can be found at https://github.com/jcnolan/NSTableViewIsGroupRowTest
Here is my tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
var text: String = "Doh!"
var aText: NSAttributedString? = nil
var cellIdentifier: CellIdentifiers? = nil
guard let item = tableData?[row] else { return nil }
if let tableColumn = tableColumn { cellIdentifier = CellIdentifiers(rawValue: String(describing: tableColumn.identifier.rawValue)) }
else { cellIdentifier = CellIdentifiers.pageCell } // When "groupRow" is true there is no column, so use first column whatever that is
if let _ = item.title { cellIdentifier = CellIdentifiers.titleRow } // hack
guard let cellIdentifier = cellIdentifier else { return nil }
if let cell = tableView.makeView(withIdentifier: cellIdentifier.uiiId, owner: nil) as? NSTableCellView {
switch cellIdentifier {
case .pageCell: text = item.page?.description ?? "page unk"; break
case .commentCell: text = item.comment ?? "comment unk"; break
case .titleRow: text = item.title ?? "title unk"
var attributes = [NSAttributedString.Key: AnyObject]()
attributes[.foregroundColor] = NSColor.white
attributes[.font] = NSFont.boldSystemFont(ofSize: 13.0)
aText = NSAttributedString(string: text, attributes: attributes)
}
if let aText = aText { cell.textField?.attributedStringValue = aText }
else { cell.textField?.stringValue = text }
return cell
}
return nil
}
And my tableView(_ tableView: NSTableView, isGroupRow row: Int)
func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
// return false // Uncomment this to see NSAttributedString working in standard row
guard let item = tableData?[row], let title = item.title else { return false }
return true // only if item exists and it's a tittle
}
The solution also requires func tableView(_ tableView: NSTableView, rowViewForRow row: Int)
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
// Required for changing table highlighting
guard let item = tableData?[row] else { return nil }
let retVal:TintedTableRowView? = TintedTableRowView()
if let retVal = retVal {
retVal.isTitleRow = item.title != nil
}
return retVal
}
class TintedTableRowView: NSTableRowView {
var isTitleRow: Bool = false
override func draw(_ dirtyRect: NSRect) {
if self.selectionHighlightStyle != .none || true {
var bgcol:NSColor = NSColor.clear
switch isTitleRow {
case true: bgcol = NSColor.lightGray
default: bgcol = NSColor.clear }
let selectionRect = NSInsetRect(self.bounds, 0, 0)
bgcol.setStroke()
bgcol.setFill()
let selectionPath = NSBezierPath.init(roundedRect: selectionRect, xRadius: 0, yRadius: 0)
selectionPath.fill()
selectionPath.stroke()
}
}
}
Based on the fact that the font gets bolded automatically I'm guessing there is another path needed to tell Swift how to format a group row? I've been struggling with this problem for several days now... any help would be greatly appreciated.
EDIT: Checking the documentation there is a reference "When configured as a source list style table view, rows identified as group rows draw with a specific style unique to source lists." However, I wasn't using the "source list" style and changing it explicitly to "plain" in both the storyboard editor and via code seems to have no effect.
EDIT2: An additional request was made for the data set... though I'm pretty sure this is related to isGroupRow and the full project can be seen at https://github.com/jcnolan/NSTableViewIsGroupRowTest. Here is the data set and viewDidLoad():
struct TableDataItem {
var title: String? = nil
var page: Int? = nil
var comment: String? = nil
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
tableView.floatsGroupRows = false
installStubData()
tableView.reloadData()
}
func installStubData() {
tableData = []
tableData!.append(TableDataItem(title: "This is doc title 1", page: nil, comment: nil))
tableData!.append(TableDataItem(title: nil, page: 1, comment: "this is doc 1, page one comment"))
tableData!.append(TableDataItem(title: nil, page: 2, comment: "this is doc 1, page two comment"))
tableData!.append(TableDataItem(title: nil, page: 3, comment: "this is doc 1, page three comment"))
tableData!.append(TableDataItem(title: "This is doc title 2", page: nil, comment: nil))
tableData!.append(TableDataItem(title: nil, page: 1, comment: "this is doc 2, page one comment"))
tableData!.append(TableDataItem(title: "This is doc title 3", page: nil, comment: nil))
tableData!.append(TableDataItem(title: nil, page: 1, comment: "this is doc 3, page one comment"))
tableData!.append(TableDataItem(title: nil, page: 2, comment: "this is doc 3, page two comment"))
}