Skip to content

FuzzyFilterProxyModel

Qt Base Class: QSortFilterProxyModel

Signature: QSortFilterProxyModel(self, parent: Optional[PySide6.QtCore.QObject] = None) -> None

Base classes

Name Children Inherits
SortFilterProxyModel
prettyqt.core.sortfilterproxymodel

⋔ Inheritance diagram

graph TD
  1473290728656["itemmodels.FuzzyFilterProxyModel"]
  1473299898960["core.SortFilterProxyModel"]
  1473299903840["core.AbstractProxyModelMixin"]
  1473299890176["core.AbstractItemModelMixin"]
  1473299815024["core.ObjectMixin"]
  140713234304496["builtins.object"]
  1473289062816["QtCore.QSortFilterProxyModel"]
  1473289061840["QtCore.QAbstractProxyModel"]
  1473289050128["QtCore.QAbstractItemModel"]
  1473288842240["QtCore.QObject"]
  1473291690208["Shiboken.Object"]
  1473299898960 --> 1473290728656
  1473299903840 --> 1473299898960
  1473299890176 --> 1473299903840
  1473299815024 --> 1473299890176
  140713234304496 --> 1473299815024
  1473289062816 --> 1473299898960
  1473289061840 --> 1473289062816
  1473289050128 --> 1473289061840
  1473288842240 --> 1473289050128
  1473291690208 --> 1473288842240
  140713234304496 --> 1473291690208

🛈 DocStrings

Bases: SortFilterProxyModel

A FilterProxyModel which sorts the results based on a matching score.

The matching score evaluates metrics like upper/lower casing, distance of filter character to match character and some more. Best matches are shown at the top.

The matching score is exposed as a custom UserRole (FuzzyFilterProxyModel.Roles.SortRole) The proxymodel replaces the text from the display role in the given filter column with HTML code in order to color the letter matches. A backup from the original text is made available in the BackupRole. Based on the original text, the proxy calculates a score for the match and makes it available via the SortRole. To display the html code properly, a HtmlItemDelegate is needed.

Example

proxy = itemmodels.FuzzyFilterProxyModel()
proxy.set_source_model(model)
table.set_model(proxy)
table.show()
Source code in prettyqt\itemmodels\proxies\fuzzyfilterproxymodel.py
class FuzzyFilterProxyModel(core.SortFilterProxyModel):
    """A FilterProxyModel which sorts the results based on a matching score.

    The matching score evaluates metrics like upper/lower casing, distance of
    filter character to match character and some more.
    Best matches are shown at the top.

    The matching score is exposed as a custom UserRole
    (FuzzyFilterProxyModel.Roles.SortRole)
    The proxymodel replaces the text from the display role in the given filter column
    with HTML code in order to color the letter matches. A backup from the original text
    is made available in the BackupRole. Based on the original text, the proxy calculates
    a score for the match and makes it available via the SortRole.
    To display the html code properly, a HtmlItemDelegate is needed.

    ### Example

    ```py
    proxy = itemmodels.FuzzyFilterProxyModel()
    proxy.set_source_model(model)
    table.set_model(proxy)
    table.show()
    ```
    """

    ID = "fuzzy"

    class Roles(enum.IntEnum):
        """Addional roles."""

        BackupRole = constants.USER_ROLE + 65
        SortRole = constants.SORT_ROLE

    def __init__(self, *args, **kwargs):
        super().__init__(*args, filter_mode="fuzzy", **kwargs)
        self._search_term = ""
        self._match_color: gui.QColor = gui.Color("blue")
        self.sort(0, constants.DESCENDING)

    def set_match_color(self, color: datatypes.ColorType | None):
        self._match_color = colors.get_color(color) if color else gui.QColor()

    def get_match_color(self) -> gui.QColor:
        return self._match_color

    def lessThan(self, left: core.ModelIndex, right: core.ModelIndex):
        if not self._search_term:
            return super().lessThan(left, right)
        if left.data() is None or right.data() is None:
            return True
        # since fuzzy scores are cached, it should be fine to do this here.
        left_data = fuzzy.fuzzy_match(self._search_term, str(left.data()))
        right_data = fuzzy.fuzzy_match(self._search_term, str(right.data()))

        return left_data < right_data

    def set_search_term(self, search_term: str):
        self._search_term = search_term
        super().set_search_term(search_term)
        self.invalidate()

    def get_search_term(self):
        return self._search_term

    def data(
        self,
        index: core.ModelIndex,
        role: constants.ItemDataRole = constants.DISPLAY_ROLE,
    ):
        if not index.isValid():
            return None
        filter_column = self.filterKeyColumn()
        match role, index.column():
            case constants.DISPLAY_ROLE, _ if index.column() == filter_column:
                label = super().data(index, constants.DISPLAY_ROLE)
                return (
                    fuzzy.color_text(
                        self._search_term,
                        str(label),
                        self._match_color.name(),
                        self.is_filter_case_sensitive(),
                    )
                    if self._search_term and self._match_color.isValid() and label
                    else label
                )
            # case constants.DISPLAY_ROLE, 1:
            #     idx = self.index(index.row(), filter_column)
            #     label = super().data(idx, constants.DISPLAY_ROLE)
            #     if label is None:
            #         return None
            #     result = fuzzy.fuzzy_match(self._search_term, str(label))
            #     return str(result[1])
            case self.Roles.BackupRole, _:
                return super().data(index, constants.DISPLAY_ROLE)
            case self.Roles.SortRole, _:
                idx = self.index(index.row(), filter_column)
                label = super().data(idx, constants.DISPLAY_ROLE)
                result = fuzzy.fuzzy_match(self._search_term, label)
                return result[1]
            case _, _:
                return super().data(index, role)

    search_term = core.Property(
        str,
        get_search_term,
        set_search_term,
        doc="Current search term",
    )
    match_color = core.Property(
        gui.QColor,
        get_match_color,
        set_match_color,
        doc="Color to use for match coloring",
    )

Roles

Bases: IntEnum

Addional roles.

Source code in prettyqt\itemmodels\proxies\fuzzyfilterproxymodel.py
class Roles(enum.IntEnum):
    """Addional roles."""

    BackupRole = constants.USER_ROLE + 65
    SortRole = constants.SORT_ROLE

⌗ Property table

Qt Property Type Doc
objectName QString
sourceModel QAbstractItemModel
filterRegularExpression QRegularExpression
filterKeyColumn int
dynamicSortFilter bool
filterCaseSensitivity Qt::CaseSensitivity
sortCaseSensitivity Qt::CaseSensitivity
isSortLocaleAware bool
sortRole int
filterRole int
recursiveFilteringEnabled bool
autoAcceptChildRows bool
filterMode QString Mode to use for filtering
search_term QString Current search term
match_color QColor Color to use for match coloring