mirror of
https://github.com/SELinuxProject/setools
synced 2025-03-31 15:56:22 +00:00
125 lines
3.6 KiB
Python
125 lines
3.6 KiB
Python
# Copyright 2016, Chris PeBenito <pebenito@ieee.org>
|
|
#
|
|
# SPDX-License-Identifier: LGPL-2.1-only
|
|
#
|
|
#
|
|
from typing import Dict, NamedTuple
|
|
from enum import Enum
|
|
|
|
import sip
|
|
from PyQt5.QtWidgets import QDialogButtonBox, QScrollArea
|
|
|
|
from ..widget import SEToolsWidget
|
|
|
|
|
|
class AnalysisSection(Enum):
|
|
|
|
"""Groupings of analysis tabs"""
|
|
|
|
Analysis = 1
|
|
Components = 2
|
|
General = 3
|
|
Labeling = 4
|
|
Other = 5
|
|
Rules = 6
|
|
|
|
|
|
TAB_REGISTRY: Dict[str, type] = {}
|
|
|
|
|
|
class TabRegistry(sip.wrappertype):
|
|
|
|
"""
|
|
Analysis tab registry metaclass. This registers tabs to be used both for
|
|
populating the content of the "choose analysis" dialog and also for
|
|
saving tab/workspace info.
|
|
"""
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
classdef = super().__new__(cls, *args, **kwargs)
|
|
|
|
clsname = args[0]
|
|
attributedict = args[2]
|
|
if clsname != "AnalysisTab":
|
|
assert "section" in attributedict, "Class {} is missing the section value, " \
|
|
"this is an setools bug".format(clsname)
|
|
|
|
assert "tab_title" in attributedict, "Class {} is missing the tab_title value, " \
|
|
"this is an setools bug".format(clsname)
|
|
|
|
assert "mlsonly" in attributedict, "Class {} is missing the mlsonly value, " \
|
|
"this is an setools bug".format(clsname)
|
|
|
|
# ensure there is no duplication of class name or title
|
|
for existing_tabname, existing_class in TAB_REGISTRY.items():
|
|
if existing_tabname == clsname:
|
|
raise TypeError("Analysis tab {} conflicts with registered tab {}, "
|
|
"this is an setools bug".format(clsname, existing_tabname))
|
|
|
|
if existing_class.tab_title == attributedict["tab_title"]:
|
|
raise TypeError("Analysis tab {}'s title \"{}\" conflicts with registered tab "
|
|
"{}, this is an setools bug.".
|
|
format(clsname, attributedict["tab_title"], existing_tabname))
|
|
|
|
TAB_REGISTRY[clsname] = classdef
|
|
|
|
return classdef
|
|
|
|
|
|
# pylint: disable=invalid-metaclass
|
|
class AnalysisTab(SEToolsWidget, QScrollArea, metaclass=TabRegistry):
|
|
|
|
"""Base class for Apol analysis tabs."""
|
|
|
|
# A QButtonBox which has an Apply button
|
|
# for running the analysis.
|
|
buttonBox = None
|
|
|
|
# The set of tab fields that are in error
|
|
errors = None
|
|
|
|
# Normal and error palettes to use
|
|
orig_palette = None
|
|
error_palette = None
|
|
|
|
#
|
|
# Tab error state
|
|
#
|
|
def set_criteria_error(self, field, error):
|
|
"""Set the specified widget to an error state."""
|
|
field.setToolTip("Error: {0}".format(error))
|
|
field.setPalette(self.error_palette)
|
|
self.errors.add(field)
|
|
self._check_query()
|
|
|
|
def clear_criteria_error(self, field, tooltip):
|
|
"""Clear the specified widget's error state."""
|
|
field.setToolTip(tooltip)
|
|
field.setPalette(self.orig_palette)
|
|
self.errors.discard(field)
|
|
self._check_query()
|
|
|
|
def _check_query(self):
|
|
button = self.buttonBox.button(QDialogButtonBox.Apply)
|
|
enabled = not self.errors
|
|
button.setEnabled(enabled)
|
|
button.setToolTip("Run the analysis." if enabled else "There are errors in the tab.")
|
|
|
|
#
|
|
# Save/Load tab
|
|
#
|
|
def save(self):
|
|
raise NotImplementedError
|
|
|
|
def load(self, settings):
|
|
raise NotImplementedError
|
|
|
|
#
|
|
# Results runner
|
|
#
|
|
def run(self, button):
|
|
raise NotImplementedError
|
|
|
|
def update_complete(self, count):
|
|
raise NotImplementedError
|