FilteringController

Demonstrates how to subclass NSArrayController to implement filtering of a NSTableView. Also demonstrates the use of indexed accessors.

Originally from “Cocoa Bindings Examples and Hints”, converted to PyObjC by u.fiedler.

Sources

FilteringArrayController.py

#
#  FilteringArrayController.py
#  FilteringController
#
#  Converted by u.fiedler on 05.02.05.
#
#  The original version was written in Objective-C by Malcolm Crawford
#  at http://homepage.mac.com/mmalc/CocoaExamples/controllers.html

from objc import super
from Cocoa import NSArrayController

class FilteringArrayController(NSArrayController):
    _k_searchString = ""

    def search_(self, sender):
        self.setSearchString_(sender.stringValue())
        self.rearrangeObjects()

    def newObject(self):
        """
        Creates and returns a new object of the class specified by objectClass.
        Set default values, and keep reference to new object -- see arrangeObjects_
        """
        self.newObj = super(FilteringArrayController, self).newObject()
        self.newObj.setValue_forKey_("First", "firstName")
        self.newObj.setValue_forKey_("Last", "lastName")
        return self.newObj

    def arrangeObjects_(self, objects):
        if self._k_searchString == None or self._k_searchString == "":
            self.newObj = None
            return super(FilteringArrayController, self).arrangeObjects_(objects)

        # Create array of objects that match search string.
        # Also add any newly-created object unconditionally:
        # (a) You'll get an error if a newly-added object isn't added to
        # arrangedObjects.
        # (b) The user will see newly-added objects even if they don't
        # match the search term.

        matchedObjects = []
        lowerSearch = self._k_searchString.lower()
        for item in objects:
            if item == self.newObj:
                # if the item has just been created, add it unconditionally
                matchedObjects.append(item)
                self.newObj = None
            else:
                lowerName = item.valueForKeyPath_("firstName").lower()
                if lowerSearch in lowerName:
                    matchedObjects.append(item)
                else:
                    lowerName = item.valueForKeyPath_("lastName").lower()
                    if lowerSearch in lowerName:
                        matchedObjects.append(item)
        return super(FilteringArrayController, self).arrangeObjects_(matchedObjects)

    def searchString(self):
        return self._k_searchString

    def setSearchString_(self, newStr):
        self._k_searchString = newStr

FilteringController.py

#
#  FilteringController
#

from PyObjCTools import AppHelper
import FilteringControllerDocument
import FilteringArrayController

AppHelper.runEventLoop()

FilteringControllerDocument.py

#
#  FilteringControllerDocument.py
#  FilteringController
#
#  Converted by u.fiedler on 05.02.05.
#
#  The original version was written in Objective-C by Malcolm Crawford
#  at http://homepage.mac.com/mmalc/CocoaExamples/controllers.html

from PyObjCTools import AppHelper
import objc
from objc import super
from Cocoa import NSDocument, NSKeyedArchiver, NSKeyedUnarchiver



class FilteringControllerDocument (NSDocument):
    peopleController = objc.IBOutlet()

    def init(self):
        self = super(FilteringControllerDocument, self).init()
        if self is None: return None
        self._k_people = []
        return self

    def windowNibName(self):
        return "FilteringControllerDocument"

    def windowControllerDidLoadNib_(self, controller):
        super(FilteringControllerDocument, self).windowControllerDidLoadNib_(controller)

    def dataRepresentationOfType_(self, aType):
        return NSKeyedArchiver.archivedDataWithRootObject_(self._k_people)

    def loadDataRepresentation_ofType_(self, data, aType):
        self.setPeople_(NSKeyedUnarchiver.unarchiveObjectWithData_(data))
        return True


    ### indexed accessors

    def people(self):
        return self._k_people

    def setPeople_(self, people):
        self._k_people[:] = people

    @objc.accessor
    def countOfPeople(self):
        return len(self._k_people)

    @objc.accessor
    def objectInPeopleAtIndex_(self, idx):
        return self._k_people[idx]

    @objc.accessor
    def insertObject_inPeopleAtIndex_(self, obj, idx):
        self._k_people.insert(idx, obj)

    @objc.accessor
    def removeObjectFromPeopleAtIndex_(self, idx):
        del self._k_people[idx]

    @objc.accessor
    def replaceObjectInPeopleAtIndex_withObject_(self, idx, obj):
        self._k_people[idx] = obj

setup.py

"""
Script for building the example:

Usage:
    python3 setup.py py2app
"""
from setuptools import setup

plist = dict(
    CFBundleDocumentTypes = [
        dict(
            CFBundleTypeExtensions=["FilteringController", "*"],
            CFBundleTypeName="FilteringController File",
            CFBundleTypeRole="Editor",
            NSDocumentClass="FilteringControllerDocument",
        ),
    ],
)

setup(
    name="FilteringController",
    app=["FilteringController.py"],
    data_files=["English.lproj"],
    options=dict(py2app=dict(
        plist=plist,
    )),
    setup_requires=[
        "py2app",
        "pyobjc-framework-Cocoa",
    ]
)

Resources