Split SEToolsTableModel and SEToolsListModel into separate modules.

Signed-off-by: Chris PeBenito <pebenito@ieee.org>
This commit is contained in:
Chris PeBenito 2023-05-18 09:04:16 -04:00 committed by Chris PeBenito
parent af7754076e
commit 40254914ae
26 changed files with 262 additions and 65 deletions

View File

@ -7,7 +7,7 @@ from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QTextCursor
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def boolean_detail(parent, boolean):
@ -33,10 +33,10 @@ class BooleanTableModel(SEToolsTableModel):
headers = ["Name", "Default State"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
boolean = self.resultlist[row]
boolean = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class BoundsTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class BoundsTableModel(SEToolsTableModel):
headers = ["Rule Type", "Parent", "Child"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -9,7 +9,7 @@ from PyQt5.QtGui import QPalette, QTextCursor
from setools.exception import NoCommon
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def common_detail(parent, common):
@ -37,10 +37,10 @@ class CommonTableModel(SEToolsTableModel):
headers = ["Name", "Permissions"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -6,7 +6,7 @@
from PyQt5.QtCore import Qt
from setools.exception import ConstraintUseError
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class ConstraintTableModel(SEToolsTableModel):
@ -16,10 +16,10 @@ class ConstraintTableModel(SEToolsTableModel):
headers = ["Rule Type", "Class", "Permissions", "Expression"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -7,7 +7,7 @@ from contextlib import suppress
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class DefaultTableModel(SEToolsTableModel):
@ -17,10 +17,10 @@ class DefaultTableModel(SEToolsTableModel):
headers = ["Rule Type", "Class", "Default", "Default Range"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class FSUseTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class FSUseTableModel(SEToolsTableModel):
headers = ["Ruletype", "FS Type", "Context"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -7,7 +7,7 @@ import stat
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class GenfsconTableModel(SEToolsTableModel):
@ -27,10 +27,10 @@ class GenfsconTableModel(SEToolsTableModel):
stat.S_IFSOCK: "Socket"}
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class IbendportconTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class IbendportconTableModel(SEToolsTableModel):
headers = ["Device", "Endport", "Context"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class IbpkeyconTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class IbpkeyconTableModel(SEToolsTableModel):
headers = ["Subnet Prefix", "Partition Keys", "Context"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class InitialSIDTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class InitialSIDTableModel(SEToolsTableModel):
headers = ["SID", "Context"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -0,0 +1,93 @@
# Copyright 2015, Tresys Technology, LLC
#
# SPDX-License-Identifier: LGPL-2.1-only
#
#
import logging
import typing
from PyQt5 import QtCore
from . import modelroles
from .typing import MetaclassFix
T = typing.TypeVar("T")
class SEToolsListModel(QtCore.QAbstractListModel, typing.Generic[T], metaclass=MetaclassFix):
"""
The purpose of this model is to have the
objects return their string representations
for Qt.DisplayRole and return the object
for Qt.UserRole.
Some Python list-like functions are provided
for altering the model: append and remove
"""
def __init__(self, parent: QtCore.QObject | None = None) -> None:
super().__init__(parent)
self.log = logging.getLogger(self.__module__)
self._item_list: typing.List[T] = []
@property
def item_list(self) -> typing.List[T]:
"""The list of items in the model."""
return self._item_list
@item_list.setter
def item_list(self, item_list: typing.List[T]) -> None:
self.beginResetModel()
self._item_list = item_list
self.endResetModel()
def rowCount(self, parent=QtCore.QModelIndex()) -> int:
"""The number of rows in the model."""
return len(self.item_list)
def columnCount(self, parent=QtCore.QModelIndex()) -> int:
"""The number of columns in the model."""
return 1
def append(self, item: T) -> None:
"""Append the item to the list."""
index = self.rowCount()
self.beginInsertRows(QtCore.QModelIndex(), index, index)
self.item_list.append(item)
self.endInsertRows()
def remove(self, item: T) -> None:
"""Remove the first instance of the specified item from the list."""
try:
row = self.item_list.index(item)
self.beginRemoveRows(QtCore.QModelIndex(), row, row)
del self.item_list[row]
self.endRemoveRows()
except ValueError:
self.log.debug(f"Attempted to remove item {item!r} but it is not in the list")
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
"""Get the data at the specified index for the specified role."""
if not self.item_list or not index.isValid():
return None
row = index.row()
item = self.item_list[row]
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
return str(item)
case modelroles.PolicyObjRole:
return item
case modelroles.ContextMenuRole:
return ()
case _:
return None
def flags(self, index: QtCore.QModelIndex = QtCore.QModelIndex()) -> QtCore.Qt.ItemFlags:
"""Get the flags for the specified index."""
return QtCore.Qt.ItemFlags() | \
QtCore.Qt.ItemFlag.ItemIsEnabled | \
QtCore.Qt.ItemFlag.ItemIsSelectable | \
QtCore.Qt.ItemFlag.ItemNeverHasChildren

View File

@ -7,7 +7,7 @@ from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette, QTextCursor
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def _mls_detail(parent, obj, objtype):
@ -58,10 +58,10 @@ class MLSComponentTableModel(SEToolsTableModel):
headers = ["Name", "Aliases"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class MLSRuleTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class MLSRuleTableModel(SEToolsTableModel):
headers = ["Rule Type", "Source", "Target", "Object Class", "Default Range"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-only
from typing import Final
from PyQt5 import QtCore
PolicyObjRole: Final[int] = QtCore.Qt.ItemDataRole.UserRole
ContextMenuRole: Final[int] = QtCore.Qt.ItemDataRole.UserRole + 1

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class NetifconTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class NetifconTableModel(SEToolsTableModel):
headers = ["Device", "Device Context", "Packet Context"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class NodeconTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class NodeconTableModel(SEToolsTableModel):
headers = ["Network", "Context"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -11,7 +11,7 @@ from PyQt5.QtGui import QPalette, QTextCursor
from setools.exception import NoCommon
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def class_detail(parent, class_):
@ -53,10 +53,10 @@ class ObjClassTableModel(SEToolsTableModel):
headers = ["Name", "Permissions"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -5,7 +5,7 @@
#
from PyQt5.QtCore import Qt
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class PortconTableModel(SEToolsTableModel):
@ -15,10 +15,10 @@ class PortconTableModel(SEToolsTableModel):
headers = ["Port/Port Range", "Protocol", "Context"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -6,7 +6,7 @@
from PyQt5.QtCore import Qt
from setools.exception import RuleUseError
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class RBACRuleTableModel(SEToolsTableModel):
@ -16,10 +16,10 @@ class RBACRuleTableModel(SEToolsTableModel):
headers = ["Rule Type", "Source", "Target", "Object Class", "Default Role"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -9,7 +9,7 @@ from PyQt5.QtGui import QPalette, QTextCursor
from setools.exception import MLSDisabled
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def role_detail(parent, role):
@ -42,10 +42,10 @@ class RoleTableModel(SEToolsTableModel):
# There are two roles here.
# The parameter, role, is the Qt role
# The below item is a role in the list.
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -0,0 +1,77 @@
# Copyright 2015, Tresys Technology, LLC
#
# SPDX-License-Identifier: LGPL-2.1-only
#
#
import logging
import typing
from PyQt5 import QtCore
from . import modelroles
from .typing import MetaclassFix
T = typing.TypeVar("T")
class SEToolsTableModel(QtCore.QAbstractTableModel, typing.Generic[T], metaclass=MetaclassFix):
"""Base class for SETools table models, modeling a list in a tabular form."""
headers: typing.List[str] = []
def __init__(self, parent: QtCore.QObject | None = None):
super().__init__(parent)
self.log = logging.getLogger(self.__module__)
self._item_list: typing.List[T] = []
@property
def item_list(self) -> typing.List[T]:
"""The list of items in the model."""
return self._item_list
@item_list.setter
def item_list(self, item_list: typing.List[T]) -> None:
self.beginResetModel()
self._item_list = item_list
self.endResetModel()
def headerData(self, section: int, orientation: QtCore.Qt.Orientation,
role: int = QtCore.Qt.ItemDataRole.DisplayRole):
if role == QtCore.Qt.ItemDataRole.DisplayRole and \
orientation == QtCore.Qt.Orientation.Horizontal:
return self.headers[section]
def rowCount(self, parent: QtCore.QModelIndex = QtCore.QModelIndex()) -> int:
"""The number of rows in the model."""
return len(self.item_list)
def columnCount(self, parent: QtCore.QModelIndex = QtCore.QModelIndex()) -> int:
"""The number of columns in the model."""
return len(self.headers)
def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
"""Get the data at the specified index for the specified role."""
if not self.item_list or not index.isValid():
return None
row = index.row()
match role:
case QtCore.Qt.ItemDataRole.DisplayRole:
raise NotImplementedError
case modelroles.PolicyObjRole:
return self.item_list[row]
case modelroles.ContextMenuRole:
return ()
case _:
return None
def flags(self, index: QtCore.QModelIndex = QtCore.QModelIndex()) -> QtCore.Qt.ItemFlags:
"""Get the flags for the specified index."""
return QtCore.Qt.ItemFlags() | \
QtCore.Qt.ItemFlag.ItemIsEnabled | \
QtCore.Qt.ItemFlag.ItemIsSelectable | \
QtCore.Qt.ItemFlag.ItemNeverHasChildren

View File

@ -6,7 +6,7 @@
from PyQt5.QtCore import Qt
from setools.exception import RuleNotConditional, RuleUseError
from .models import SEToolsTableModel
from .table import SEToolsTableModel
class TERuleTableModel(SEToolsTableModel):
@ -17,10 +17,10 @@ class TERuleTableModel(SEToolsTableModel):
"Conditional Expression", "Conditional Block"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
rule = self.resultlist[row]
rule = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -9,7 +9,7 @@ from PyQt5.QtGui import QPalette, QTextCursor
from setools.exception import MLSDisabled
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def type_detail(parent, type_):
@ -45,10 +45,10 @@ class TypeTableModel(SEToolsTableModel):
headers = ["Name", "Attributes", "Aliases", "Permissive"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -9,7 +9,7 @@ from PyQt5.QtGui import QPalette, QTextCursor
from setools.exception import MLSDisabled
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def typeattr_detail(parent, attr):
@ -39,10 +39,10 @@ class TypeAttributeTableModel(SEToolsTableModel):
headers = ["Name", "Types"]
def data(self, index, role):
if self.resultlist and index.isValid():
if self.item_list and index.isValid():
row = index.row()
col = index.column()
item = self.resultlist[row]
item = self.item_list[row]
if role == Qt.ItemDataRole.DisplayRole:
if col == 0:

View File

@ -0,0 +1,20 @@
# SPDX-License-Identifier: LGPL-2.1-only
import abc
from PyQt5 import QtCore
QObjectType: type = type(QtCore.QObject)
class MetaclassFix(QObjectType, abc.ABC):
"""
Fix metaclass issues.
Use this when doing a Generic[] with a PyQt type. Fixes this error:
TypeError: metaclass conflict: the metaclass of a derived class must be a
(non-strict) subclass of the metaclasses of all its bases
"""
pass

View File

@ -7,7 +7,7 @@ from PyQt5.QtCore import Qt, QModelIndex
from setools.exception import MLSDisabled
from .details import DetailsPopup
from .models import SEToolsTableModel
from .table import SEToolsTableModel
def user_detail(parent, user):
@ -59,7 +59,7 @@ class UserTableModel(SEToolsTableModel):
if role == Qt.ItemDataRole.DisplayRole:
row = index.row()
col = index.column()
user = self.resultlist[row]
user = self.item_list[row]
if col == 0:
return user.name