Resetting a NSPredicate

Hi,

I use a predicate to filter a NSTableView when I type in a NSSearchField :

private func _filterTracks(str: String) {

        var thePredicates = [NSPredicate]()

        let theArtistPredicate = NSPredicate(format: FilterType.format, FilterType.artistField, str)

        let theTitlePredicate = NSPredicate(format: FilterType.format, FilterType.titleField, str)

        let theAlbumPredicate = NSPredicate(format: FilterType.format, FilterType.albumField, str)

        

        switch _filter?.tag {

        case FilterType.FilterListType.ALL.rawValue:

            thePredicates.append(theArtistPredicate)

            thePredicates.append(theTitlePredicate)

            thePredicates.append(theAlbumPredicate)

        case FilterType.FilterListType.artist.rawValue:

            thePredicates.append(theArtistPredicate)

        case FilterType.FilterListType.album.rawValue:

            thePredicates.append(theAlbumPredicate)

        case FilterType.FilterListType.title.rawValue:

            thePredicates.append(theTitlePredicate)

        default:

            thePredicates.append(theArtistPredicate)

            thePredicates.append(theTitlePredicate)

            thePredicates.append(theAlbumPredicate)

        }

        let theCompoundPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.or, subpredicates: thePredicates)

        arrayController.filterPredicate = theCompoundPredicate

    }

But when the NSSearchField is reset, how to reset the filter and get the datas in the NSTableView like it was ?

Thx.

Accepted Reply

Yes, searchFieldDidEndSearching is called each time the NSSearchField is cleared. It is working.

And _filterTracks is called each time a char is typed in the NSSearchField in the controlTextDidChange method :

func controlTextDidChange(_ obj: Notification) {
        let theTextField = obj.object as! NSTextField
        let theStr = theTextField.stringValue
        _filterTracks(str: theStr)
    }

So each time a char is typed, the predicate is set to the NSArrayController.

And after that, I "just" need to find how to clear the predicate once the NSSearchField is cleared, like we have in iTunes / Music app...

Thx.

  • So, why don't you call _filterTracks(str: "") in searchFieldDidEndSearching ?

  • I tried : func searchFieldDidEndSearching(_ sender: NSSearchField) {         _filterTracks(str: "") }

    And same result >>> the NSTableView is empty now... Logical because it's looking for items which contains an empty string and there is not...

    Or is there a reloadData() or something to call is this case ?

Add a Comment

Replies

Check what is the string value you passed:

private func _filterTracks(str: String) {
    print("filter string is", str, "---")

Where do you set filter tag, and how ?

Thx for you answer.

My question is not about how to test if the filter must be reset but how to reset it.

To know when the filter must be reset, I use the NSSearchField searchFieldDidEndSearching method. I tried to set the predicate to nil but it doesn't work :

func searchFieldDidEndSearching(_ sender: NSSearchField) {

        print("V&G_Project___TrackListView searchFieldDidEndSearching : ", self)

        arrayController.filterPredicate = nil

    }

The _filter var is used to change the predicate because I can change the filter type :

At first I tried with the NSSearchField bind method directly and it is working :

searchField.bind(.predicate, to: arrayController, withKeyPath: NSBindingName.filterPredicate.rawValue, options: [.predicateFormat: "(title contains[cd] $value) OR (artist.name CONTAINS[cd] $value)"])

Problem : I didn't find how to change the NSPredicate one another filter is selected...

Thx for your help.

I tried to use the NSSearchField bind method with my function to change the filter and it is working.

So something is done by the NSSearchField bind method to reset the predicate and get the NSArrayController datas like it was before the predicate is executed when the reset button is pressed.

How to do that programmatically ?

I've already read this post.

It helped me to understand the multiple predicates but it is not about how to reset it because it is done automatically by the NSSearchField. Also, it is done in the Xcode Storyboard.

Me, I'd like to do it programmatically.

I just have to know what to call in the searchFieldDidEndSearching NSSearchField method...

Do you know ?

Thx.

So, you checked that searchFieldDidEndSearching is called ?

func searchFieldDidEndSearching(_ sender: NSSearchField) {

        print("V&G_Project___TrackListView searchFieldDidEndSearching : ", self)
        arrayController.filterPredicate = nil

    }

But how could arrayController.filterPredicate be set to nil ? Is filterPredicate really an optional ?

Where do you call _filterTracks ?

Yes, searchFieldDidEndSearching is called each time the NSSearchField is cleared. It is working.

And _filterTracks is called each time a char is typed in the NSSearchField in the controlTextDidChange method :

func controlTextDidChange(_ obj: Notification) {
        let theTextField = obj.object as! NSTextField
        let theStr = theTextField.stringValue
        _filterTracks(str: theStr)
    }

So each time a char is typed, the predicate is set to the NSArrayController.

And after that, I "just" need to find how to clear the predicate once the NSSearchField is cleared, like we have in iTunes / Music app...

Thx.

  • So, why don't you call _filterTracks(str: "") in searchFieldDidEndSearching ?

  • I tried : func searchFieldDidEndSearching(_ sender: NSSearchField) {         _filterTracks(str: "") }

    And same result >>> the NSTableView is empty now... Logical because it's looking for items which contains an empty string and there is not...

    Or is there a reloadData() or something to call is this case ?

Add a Comment

After a while being stucked with this problem, I finally found the solution in 5 minutes :

When a NSSearchField is cleared, 2 functions are called : controlTextDidChange and searchFieldDidEndSearching.

So I just add a control to check if the filter string count is equal to 0 to reset the filter :

private func _filterTracks(str: String) {
        if str.count == 0 {
            resetFilter()
            return
        }
        var thePredicates = [NSPredicate]()
        let theArtistPredicate = NSPredicate(format: FilterType.format, FilterType.artistField, str)
        let theTitlePredicate = NSPredicate(format: FilterType.format, FilterType.titleField, str)
        let theAlbumPredicate = NSPredicate(format: FilterType.format, FilterType.albumField, str)
        
        if(_currentFilter?.tag == FilterType.FilterListType.ALL.rawValue){
            thePredicates.append(theArtistPredicate)
            thePredicates.append(theTitlePredicate)
            thePredicates.append(theAlbumPredicate)
        }else if(_currentFilter?.tag == FilterType.FilterListType.artist.rawValue){
            thePredicates.append(theArtistPredicate)
        }else if(_currentFilter?.tag == FilterType.FilterListType.album.rawValue){
            thePredicates.append(theAlbumPredicate)
        }else if(_currentFilter?.tag == FilterType.FilterListType.title.rawValue){
            thePredicates.append(theTitlePredicate)
        }
        
        let theCompoundPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.or, subpredicates: thePredicates)
        arrayController.filterPredicate = theCompoundPredicate
        
        print("V&G_Project____filterTracks : ", arrayController.filterPredicate?.predicateFormat)
    }
    
    func resetFilter() {
        searchField.stringValue = "" // in case the func is called from another func
        arrayController.filterPredicate = nil
    }

Et voila...

So that's right it is arrayController.filterPredicate = nil to reset the predicate.

Thx.