Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove sort indicator from NSTableView

How can I remove the sort indicator from an NSTableView that allows sorting? I am working in Xcode 8.3.x and programming with Swift 3 for macOS.

I have an NSTableView as a property of an NSViewController. I have implemented sorting when the user clicks on a Title cell. This all works as expected.

When the table is first loaded, it is unsorted and there is no sort indicator visible (this is desired behavior). After a title cell has been clicked, the data is properly sorted and a sort indicator is added to the header cell. Again all good so far.

Now I have a button to reload the unsorted table. Clicking the button does successfully reload the data (unsorted), but the sort indicator is still present (but misleading). I would like to remove the sort indicator when the "load unsorted" button is pressed because the indicator is now wrong (the list is not sorted), yet the indicator is still visible from the last sort prior to pressing the "load unsorted" button.

I have tried tableView.setIndicatorImage(newImage, in: column) in an attempt to set the indicator to nil or to a 1 pixel image but it does nothing.

I have also tried drawSortIndicator without success.

In order to have the table initially load with unsorted data, I have added a sort for a non-existent column and on the initial load, I sort on that column. This allows me to always show a sorted list - with unsorted actually sorted on column "None".

So, ultimately, I want the table loaded without sorting. I want to allow sorting, and I want to be able to reload as unsorted, thus removing any sort indicator that may be present.

class AppInfoViewController: NSViewController {

    @IBOutlet weak var tableView: NSTableView!

    var dataDict: [AppInfo] = AppInfoManager.sharedInstance.appInfoArray
    var sortOrder = AppInfoManager.ColumnOrder.None
    var sortAscending = true

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        tableView.delegate = self
        tableView.dataSource = self
        tableView.target = nil

        let descriptor_0 = NSSortDescriptor(key: AppInfoManager.ColumnOrder.Name.rawValue, ascending: true)
        let descriptor_1 = NSSortDescriptor(key: AppInfoManager.ColumnOrder.Date.rawValue, ascending: true)
        let descriptor_2 = NSSortDescriptor(key: AppInfoManager.ColumnOrder.Size.rawValue, ascending: true)

        tableView.tableColumns[0].sortDescriptorPrototype = descriptor_0
        tableView.tableColumns[1].sortDescriptorPrototype = descriptor_1
        tableView.tableColumns[2].sortDescriptorPrototype = descriptor_2
    }

    override func viewWillAppear() {
        super.viewWillAppear()
        loadSortedData()
    }

    @IBAction func reloadUnsortedData(_ sender: Any) {
        dataDict = AppInfoManager.sharedInstance.appInfoArray
        sortOrder = AppInfoManager.ColumnOrder.None
        sortAscending = false
        let column = tableView.tableColumns[0]

        //tableView.setIndicatorImage(nil, in: column)
        //tableView.headerView?.needsDisplay = true
        //tableView.headerView?.display()

        column.headerCell.drawSortIndicator(withFrame: column.headerCell.sortIndicatorRect(forBounds: (tableView.headerView?.frame)!), in: column.tableView!, ascending: false, priority: 1)
        tableView.reloadData()
    }

    func loadSortedData() {
        dataDict = AppInfoManager.sharedInstance.contentsOrderedBy(sortOrder, ascending: sortAscending)
        tableView.reloadData()
    }
}

In AppInfoManager class, the sort is accomplished like follows:

class AppInfoManager {

    static let sharedInstance: AppInfoManager = AppInfoManager()
    var appInfoArray:[AppInfo] = [AppInfo]()

    public enum ColumnOrder: String {
        case None
        case Name
        case Date
        case Size
    }

    func contentsOrderedBy(_ orderedBy: ColumnOrder, ascending: Bool) -> [AppInfo] {
        let sortedFiles: [AppInfo]
        switch orderedBy {
            case .Name:
                if ascending == true {
                    sortedFiles = appInfoArray.sorted(by: {$0.appTitle < $1.appTitle })
                } else {
                    sortedFiles = appInfoArray.sorted(by: {$0.appTitle > $1.appTitle })
                }
            case .Date:
                if ascending == true {
                    sortedFiles = appInfoArray.sorted(by: {$0.pid < $1.pid })
                } else {
                    sortedFiles = appInfoArray.sorted(by: {$0.pid > $1.pid })
                }
            case .Size:
                if ascending == true {
                    sortedFiles = appInfoArray.sorted(by: {$0.executableName < $1.executableName })
                } else {
                    sortedFiles = appInfoArray.sorted(by: {$0.executableName > $1.executableName })
                }
            case .None:
                sortedFiles = appInfoArray
        }
        return sortedFiles
    }
}

In AppInfoViewController (NSTableViewDataSource)

extension AppInfoViewController: NSTableViewDataSource {

    func numberOfRows(in tableView: NSTableView) -> Int {
        return dataDict.count
    }

    func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
        guard let sortDescriptor = tableView.sortDescriptors.first else {
            return
        }

        if let order = AppInfoManager.ColumnOrder(rawValue: sortDescriptor.key!) {
            sortOrder = order
            sortAscending = sortDescriptor.ascending
            loadSortedData()
        }
    }
}
like image 850
RGB World Avatar asked Oct 26 '25 05:10

RGB World


1 Answers

To remove sorting from the table, set a variable equal to an empty array of NSSortDescriptors, then set the table's sortDescriptors to the empty array and call reloadData().

class AppInfoViewController: NSViewController {
    let defaultSortDescriptors = [NSSortDescriptor]()
}

@IBAction func reloadUnsortedData(_ sender: Any) {
    tableView.sortDescriptors = defaultSortDescriptors
    tableView.reloadData()
}
like image 177
RGB World Avatar answered Oct 28 '25 20:10

RGB World



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!