TableModelWithSearch

A PyObjC Example without documentation

Sources

FilteringArrayController.py

#
#  FilteringArrayController.py
#  TableModelWithSearch
#
#  Created by Bill Bumgarner on Sun Apr 04 2004.
#  Copyright (c) 2004 __MyCompanyName__. All rights reserved.
#

import re

import objc
from Cocoa import NSArrayController
from objc import super  # noqa: A004

kLiteralSearch = "Literal Search"
kRegularExpressionSearch = "Regular Expression Search"


def regexForSearchString(searchString, searchType):
    if not searchString:
        return None

    searchString = searchString.strip()
    if searchType == kLiteralSearch:
        searchString = re.escape(searchString.strip()) + r"(?i)"
    return re.compile(searchString)


def dictValueFilter(dicts, regex):
    for dct in dicts:
        for value in dct.values():
            if regex.search(value):
                yield dct
                break


class FilteringArrayController(NSArrayController):
    searchString = None
    lastRegex = None
    searchType = kLiteralSearch

    def arrangeObjects_(self, objects):
        supermethod = super().arrangeObjects_
        try:
            regex = regexForSearchString(self.searchString, self.searchType)
        except:  # noqa: E722, B001
            regex = self.lastRegex
        self.lastRegex = regex
        if regex is None:
            return supermethod(objects)
        return supermethod(list(dictValueFilter(objects, regex)))

    @objc.IBAction
    def performSearch_(self, sender):
        self.searchString = sender.stringValue()
        self.rearrangeObjects()

    @objc.IBAction
    def changeSearchType_(self, searchType):
        self.lastRegex = None
        self.searchString = None
        self.searchType = searchType
        self.rearrangeObjects()

TableModelWithSearchAppDelegate.py

import pwd

from Foundation import NSMutableArray, NSObject


def getPasswords():
    a = NSMutableArray()
    for pw in pwd.getpwall():
        a.append(
            {
                "name": pw.pw_name,
                "password": pw.pw_passwd,
                "uid": str(pw.pw_uid),
                "gid": str(pw.pw_gid),
                "gecos": pw.pw_gecos,
                "home_dir": pw.pw_dir,
                "shell": pw.pw_shell,
            }
        )

    return a


class TableModelWithSearchAppDelegate(NSObject):
    def passwords(self):
        if not hasattr(self, "_cachedpasswords"):
            self._cachedpasswords = getPasswords()
        return self._cachedpasswords

ToolbarCreator.py

#
#  ToolbarCreator.py
#  TableModelWithSearch
#
#  Created by Bill Bumgarner on Sun Apr 04 2004.
#  Copyright (c) 2004 __MyCompanyName__. All rights reserved.
#

import objc
from Cocoa import (
    NSMenu,
    NSMenuItem,
    NSObject,
    NSToolbar,
    NSToolbarCustomizeToolbarItemIdentifier,
    NSToolbarFlexibleSpaceItemIdentifier,
    NSToolbarItem,
    NSToolbarPrintItemIdentifier,
    NSToolbarSeparatorItemIdentifier,
    NSToolbarSpaceItemIdentifier,
)
from FilteringArrayController import kLiteralSearch, kRegularExpressionSearch

kToolbarIdentifier = "TableModel Toolbar Identifier"
kSearchFieldItemIdentifier = "TableModel Search Field Identifier"


class ToolbarCreator(NSObject):
    filteringArrayController = objc.IBOutlet()
    searchField = objc.IBOutlet()
    window = objc.IBOutlet()

    def awakeFromNib(self):
        self.toolbarItemCache = {}

        # create toolbar containing search field
        toolbar = NSToolbar.alloc().initWithIdentifier_(kToolbarIdentifier)
        toolbar.setDelegate_(self)
        toolbar.setAllowsUserCustomization_(True)
        toolbar.setAutosavesConfiguration_(True)

        searchFieldItem = NSToolbarItem.alloc().initWithItemIdentifier_(
            kSearchFieldItemIdentifier
        )
        self.searchFieldItem = searchFieldItem
        searchFieldItem.setLabel_("Search")
        searchFieldItem.setPaletteLabel_("Search Field")
        searchFieldItem.setToolTip_("Search")
        searchFieldItem.setView_(self.searchField)
        searchFieldItem.setMinSize_(self.searchField.bounds().size)
        maxSize = self.searchField.bounds().size
        maxSize.width = maxSize.width + 150
        searchFieldItem.setMaxSize_(maxSize)

        self.toolbarItemCache[kSearchFieldItemIdentifier] = searchFieldItem

        self.window.setToolbar_(toolbar)

        cellMenu = NSMenu.alloc().initWithTitle_("Search Menu")
        # note, bottom up!
        for v in [kRegularExpressionSearch, kLiteralSearch]:
            item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
                v, "changeSearchType:", ""
            )
            item.setRepresentedObject_(v)
            item.setTarget_(self)
            cellMenu.insertItem_atIndex_(item, 0)
        self.searchField.cell().setSearchMenuTemplate_(cellMenu)
        # this better be the kLiteralSearch menu item
        self.changeSearchType_(item)

    @objc.IBAction
    def changeSearchType_(self, sender):
        obj = sender.representedObject()
        self.searchField.cell().setPlaceholderString_(obj)
        self.searchField.setStringValue_("")
        self.filteringArrayController.changeSearchType_(obj)

    def toolbarDefaultItemIdentifiers_(self, aToolbar):
        return [
            kSearchFieldItemIdentifier,
            NSToolbarFlexibleSpaceItemIdentifier,
            NSToolbarSeparatorItemIdentifier,
            NSToolbarCustomizeToolbarItemIdentifier,
        ]

    def toolbarAllowedItemIdentifiers_(self, aToolbar):
        return [
            kSearchFieldItemIdentifier,
            NSToolbarFlexibleSpaceItemIdentifier,
            NSToolbarSpaceItemIdentifier,
            NSToolbarSeparatorItemIdentifier,
            NSToolbarPrintItemIdentifier,
            NSToolbarCustomizeToolbarItemIdentifier,
        ]

    def toolbar_itemForItemIdentifier_willBeInsertedIntoToolbar_(
        self, toolbar, itemIdentifier, flag
    ):
        newItem = NSToolbarItem.alloc().initWithItemIdentifier_(itemIdentifier)
        item = self.toolbarItemCache[itemIdentifier]

        newItem.setLabel_(item.label())
        newItem.setPaletteLabel_(item.paletteLabel())
        if item.view():
            newItem.setView_(item.view())
        else:
            newItem.setImage_(item.image())

        newItem.setToolTip_(item.toolTip())
        newItem.setTarget_(item.target())
        newItem.setAction_(item.action())
        newItem.setMenuFormRepresentation_(item.menuFormRepresentation())

        if newItem.view():
            newItem.setMinSize_(item.minSize())
            newItem.setMaxSize_(item.maxSize())

        return newItem

main.py

#
#  __main__.py
#  TableModelWithSearch
#
#  Created by Bob Ippolito on Sun Apr 04 2004.
#  Copyright (c) 2004 Bob Ippolito. All rights reserved.
#

# import classes required to start application
import FilteringArrayController  # noqa: F401
import TableModelWithSearchAppDelegate  # noqa: F401
import ToolbarCreator  # noqa: F401
from PyObjCTools import AppHelper

# start the event loop
AppHelper.runEventLoop(argv=[])

setup.py

"""
Script for building the example, alternative to the Xcode project

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

setup(
    name="TableModelWithSearch",
    app=["main.py"],
    data_files=["English.lproj"],
    setup_requires=["py2app", "pyobjc-framework-Cocoa"],
)