pseudofish

powered by text files

python

Adding Filtering to list by subclassing an NSArrayController

In the previous series of articles, we’ve covered getting started, basic Address Book usage, and making an app bundle. This time, we’ll look at adding in some basic filtering to the list of dates.

To add filtering, we need to extend the NSArrayController class. The first step is to create a new python class, ArrayControllerWithSearch. This will extend the standard array controller with a search method.

from PyObjCTools import NibClassBuilder

class ArrayControllerWithSearch(NibClassBuilder.AutoBaseClass):
    searchString = None

    def search_(self, sender):
        self.searchString = sender.stringValue()

This doesn’t do anything particularly interesting, except to store the search string for the other methods to use. The AutoBaseClass means that the class we are going to derive from will be specified in Interface Builder and then allocated dynamically.

The next step is to over-ride the method that actually lists the objects in the array, arrangeObjects_. (recalling that the underscore is required for when Objective C wants a ‘:’).

def arrangeObjects_(self, objects):
    # retrieve a reference to the same method in the base class
    supermethod = super(ArrayControllerWithSearch, self).arrangeObjects_

    if self.searchString is None or self.searchString == '':
        return supermethod(objects)

    return supermethod(list(filterObjects(objects, self.searchString)))

The supermethod variable is actually a function pointer to the arrangeObjects_ method on the super class. This gets used under either case, so it is easier to have the code to access this in one place.

filterObjects will be defined next. The search is going to be rather simplistic in that it will check if the search string is contained within the name of the person.

def filterObjects(objs, searchString):
    lowerSearch = searchString.lower()
    for obj in objs:
        if(lowerSearch in obj['name'].lower()):
            yield obj
        continue

Also, add an import statement for the class in the main application (main.py):

from PyObjCTools import AppHelper
import DateListDelegate
import ArrayControllerWithSearch

AppHelper.runEventLoop(argv=[])

In Interface Builder, subclass NSArrayController in the Classes tab, and call the sub class the same name as your custom controller (ArrayControllerWithSearch). In the Attributes section of the Inspector (with the Classes tab still selected), add a new Action, called search:

From the Instances tab, select the NSArrayController for the list of names. In the Inspector, select Custom Class, and then select the new controller class:

ArrayControllerWithSearch subclass

Add a search control to the form. This will call the search_ method added to the controller.

Search control

Now, Ctrl-drag from the search control to the array controller in the Instances tab. This creates a connection. Select the search: action and then press the Connect button.

Congratulations! You now have a searchable list of birthdays for all your friends and family, integrated into your Address Book.

The complete example is available here and includes a working application bundle in dist/.