ayon-core/openpype/tools/pyblish_pype/model.py
2021-08-05 12:23:43 +02:00

1107 lines
35 KiB
Python

"""Qt models
Description:
The model contains the original objects from Pyblish, such as
pyblish.api.Instance and pyblish.api.Plugin. The model then
provides an interface for reading and writing to those.
GUI data:
Aside from original data, such as pyblish.api.Plugin.optional,
the GUI also hosts data internal to itself, such as whether or
not an item has processed such that it may be colored appropriately
in the view. This data is prefixed with two underscores (__).
E.g.
_has_processed
This is so that the the GUI-only data doesn't accidentally overwrite
or cause confusion with existing data in plug-ins and instances.
Roles:
Data is accessed via standard Qt "roles". You can think of a role
as the key of a dictionary, except they can only be integers.
"""
from __future__ import unicode_literals
import pyblish
from . import settings, util
from .awesome import tags as awesome
import Qt
from Qt import QtCore, QtGui
from six import text_type
from .vendor import qtawesome
from .constants import PluginStates, InstanceStates, GroupStates, Roles
from openpype.api import get_system_settings
# ItemTypes
InstanceType = QtGui.QStandardItem.UserType
PluginType = QtGui.QStandardItem.UserType + 1
GroupType = QtGui.QStandardItem.UserType + 2
TerminalLabelType = QtGui.QStandardItem.UserType + 3
TerminalDetailType = QtGui.QStandardItem.UserType + 4
class QAwesomeTextIconFactory:
icons = {}
@classmethod
def icon(cls, icon_name):
if icon_name not in cls.icons:
cls.icons[icon_name] = awesome.get(icon_name)
return cls.icons[icon_name]
class QAwesomeIconFactory:
icons = {}
@classmethod
def icon(cls, icon_name, icon_color):
if icon_name not in cls.icons:
cls.icons[icon_name] = {}
if icon_color not in cls.icons[icon_name]:
cls.icons[icon_name][icon_color] = qtawesome.icon(
icon_name,
color=icon_color
)
return cls.icons[icon_name][icon_color]
class IntentModel(QtGui.QStandardItemModel):
"""Model for QComboBox with intents.
It is expected that one inserted item is dictionary.
Key represents #Label and Value represent #Value.
Example:
{
"Testing": "test",
"Publishing": "publish"
}
First and default value is {"< Not Set >": None}
"""
default_item = {"< Not Set >": None}
def __init__(self, parent=None):
super(IntentModel, self).__init__(parent)
self._item_count = 0
self.default_index = 0
@property
def has_items(self):
return self._item_count > 0
def reset(self):
self.clear()
self._item_count = 0
self.default_index = 0
intents_preset = (
get_system_settings()
.get("modules", {})
.get("ftrack", {})
.get("intent", {})
)
default = intents_preset.get("default")
items = intents_preset.get("items", {})
if not items:
return
for idx, item_value in enumerate(items.keys()):
if item_value == default:
self.default_index = idx
break
self.add_items(items)
def add_items(self, items):
for value, label in items.items():
new_item = QtGui.QStandardItem()
new_item.setData(label, QtCore.Qt.DisplayRole)
new_item.setData(value, Roles.IntentItemValue)
self.setItem(self._item_count, new_item)
self._item_count += 1
class PluginItem(QtGui.QStandardItem):
"""Plugin item implementation."""
def __init__(self, plugin):
super(PluginItem, self).__init__()
item_text = plugin.__name__
if settings.UseLabel:
if hasattr(plugin, "label") and plugin.label:
item_text = plugin.label
self.plugin = plugin
self.setData(item_text, QtCore.Qt.DisplayRole)
self.setData(False, Roles.IsEnabledRole)
self.setData(0, Roles.PublishFlagsRole)
self.setData(0, Roles.PluginActionProgressRole)
icon_name = ""
if hasattr(plugin, "icon") and plugin.icon:
icon_name = plugin.icon
icon = QAwesomeTextIconFactory.icon(icon_name)
self.setData(icon, QtCore.Qt.DecorationRole)
actions = []
if hasattr(plugin, "actions") and plugin.actions:
actions = list(plugin.actions)
plugin.actions = actions
is_checked = True
is_optional = getattr(plugin, "optional", False)
if is_optional:
is_checked = getattr(plugin, "active", True)
plugin.active = is_checked
plugin.optional = is_optional
self.setData(
"{}.{}".format(plugin.__module__, plugin.__name__),
Roles.ObjectUIdRole
)
self.setFlags(
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
)
def type(self):
return PluginType
def data(self, role=QtCore.Qt.DisplayRole):
if role == Roles.IsOptionalRole:
return self.plugin.optional
if role == Roles.ObjectIdRole:
return self.plugin.id
if role == Roles.TypeRole:
return self.type()
if role == QtCore.Qt.CheckStateRole:
return self.plugin.active
if role == Roles.PathModuleRole:
return self.plugin.__module__
if role == Roles.FamiliesRole:
return self.plugin.families
if role == Roles.DocstringRole:
return self.plugin.__doc__
if role == Roles.PluginActionsVisibleRole:
return self._data_actions_visible()
if role == Roles.PluginValidActionsRole:
return self._data_valid_actions()
return super(PluginItem, self).data(role)
def _data_actions_visible(self):
# Can only run actions on active plug-ins.
if not self.plugin.active or not self.plugin.actions:
return False
publish_states = self.data(Roles.PublishFlagsRole)
if (
not publish_states & PluginStates.IsCompatible
or publish_states & PluginStates.WasSkipped
):
return False
# Context specific actions
for action in self.plugin.actions:
if action.on == "failed":
if publish_states & PluginStates.HasError:
return True
elif action.on == "succeeded":
if (
publish_states & PluginStates.WasProcessed
and not publish_states & PluginStates.HasError
):
return True
elif action.on == "processed":
if publish_states & PluginStates.WasProcessed:
return True
elif action.on == "notProcessed":
if not publish_states & PluginStates.WasProcessed:
return True
return False
def _data_valid_actions(self):
valid_actions = []
# Can only run actions on active plug-ins.
if not self.plugin.active or not self.plugin.actions:
return valid_actions
if not self.plugin.active or not self.plugin.actions:
return False
publish_states = self.data(Roles.PublishFlagsRole)
if (
not publish_states & PluginStates.IsCompatible
or publish_states & PluginStates.WasSkipped
):
return False
# Context specific actions
for action in self.plugin.actions:
valid = False
if action.on == "failed":
if publish_states & PluginStates.HasError:
valid = True
elif action.on == "succeeded":
if (
publish_states & PluginStates.WasProcessed
and not publish_states & PluginStates.HasError
):
valid = True
elif action.on == "processed":
if publish_states & PluginStates.WasProcessed:
valid = True
elif action.on == "notProcessed":
if not publish_states & PluginStates.WasProcessed:
valid = True
if valid:
valid_actions.append(action)
if not valid_actions:
return valid_actions
actions_len = len(valid_actions)
# Discard empty groups
indexex_to_remove = []
for idx, action in enumerate(valid_actions):
if action.__type__ != "category":
continue
next_id = idx + 1
if next_id >= actions_len:
indexex_to_remove.append(idx)
continue
next = valid_actions[next_id]
if next.__type__ != "action":
indexex_to_remove.append(idx)
for idx in reversed(indexex_to_remove):
valid_actions.pop(idx)
return valid_actions
def setData(self, value, role=None):
if role is None:
role = QtCore.Qt.UserRole + 1
if role == QtCore.Qt.CheckStateRole:
if not self.data(Roles.IsEnabledRole):
return False
self.plugin.active = value
self.emitDataChanged()
return
elif role == Roles.PluginActionProgressRole:
if isinstance(value, list):
_value = self.data(Roles.PluginActionProgressRole)
for flag in value:
_value |= flag
value = _value
elif isinstance(value, dict):
_value = self.data(Roles.PluginActionProgressRole)
for flag, _bool in value.items():
if _bool is True:
_value |= flag
elif _value & flag:
_value ^= flag
value = _value
elif role == Roles.PublishFlagsRole:
if isinstance(value, list):
_value = self.data(Roles.PublishFlagsRole)
for flag in value:
_value |= flag
value = _value
elif isinstance(value, dict):
_value = self.data(Roles.PublishFlagsRole)
for flag, _bool in value.items():
if _bool is True:
_value |= flag
elif _value & flag:
_value ^= flag
value = _value
if value & PluginStates.HasWarning:
if self.parent():
self.parent().setData(
{GroupStates.HasWarning: True},
Roles.PublishFlagsRole
)
if value & PluginStates.HasError:
if self.parent():
self.parent().setData(
{GroupStates.HasError: True},
Roles.PublishFlagsRole
)
return super(PluginItem, self).setData(value, role)
class GroupItem(QtGui.QStandardItem):
def __init__(self, *args, **kwargs):
self.order = kwargs.pop("order", None)
self.publish_states = 0
super(GroupItem, self).__init__(*args, **kwargs)
def flags(self):
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
def data(self, role=QtCore.Qt.DisplayRole):
if role == Roles.PublishFlagsRole:
return self.publish_states
if role == Roles.TypeRole:
return self.type()
return super(GroupItem, self).data(role)
def setData(self, value, role=(QtCore.Qt.UserRole + 1)):
if role == Roles.PublishFlagsRole:
if isinstance(value, list):
_value = self.data(Roles.PublishFlagsRole)
for flag in value:
_value |= flag
value = _value
elif isinstance(value, dict):
_value = self.data(Roles.PublishFlagsRole)
for flag, _bool in value.items():
if _bool is True:
_value |= flag
elif _value & flag:
_value ^= flag
value = _value
self.publish_states = value
self.emitDataChanged()
return True
return super(GroupItem, self).setData(value, role)
def type(self):
return GroupType
class PluginModel(QtGui.QStandardItemModel):
def __init__(self, controller, *args, **kwargs):
super(PluginModel, self).__init__(*args, **kwargs)
self.controller = controller
self.checkstates = {}
self.group_items = {}
self.plugin_items = {}
def reset(self):
self.group_items = {}
self.plugin_items = {}
self.clear()
def append(self, plugin):
plugin_groups = self.controller.order_groups.groups()
label = None
order = None
for _order, _label in reversed(plugin_groups.items()):
if _order is None or plugin.order < _order:
label = _label
order = _order
else:
break
if label is None:
label = "Other"
group_item = self.group_items.get(label)
if not group_item:
group_item = GroupItem(label, order=order)
self.appendRow(group_item)
self.group_items[label] = group_item
new_item = PluginItem(plugin)
group_item.appendRow(new_item)
self.plugin_items[plugin._id] = new_item
def store_checkstates(self):
self.checkstates.clear()
for plugin_item in self.plugin_items.values():
if not plugin_item.plugin.optional:
continue
uid = plugin_item.data(Roles.ObjectUIdRole)
self.checkstates[uid] = plugin_item.data(QtCore.Qt.CheckStateRole)
def restore_checkstates(self):
for plugin_item in self.plugin_items.values():
if not plugin_item.plugin.optional:
continue
uid = plugin_item.data(Roles.ObjectUIdRole)
state = self.checkstates.get(uid)
if state is not None:
plugin_item.setData(state, QtCore.Qt.CheckStateRole)
def update_with_result(self, result):
plugin = result["plugin"]
item = self.plugin_items[plugin.id]
new_flag_states = {
PluginStates.InProgress: False,
PluginStates.WasProcessed: True
}
publish_states = item.data(Roles.PublishFlagsRole)
has_warning = publish_states & PluginStates.HasWarning
new_records = result.get("records") or []
if not has_warning:
for record in new_records:
level_no = record.get("levelno")
if level_no and level_no >= 30:
new_flag_states[PluginStates.HasWarning] = True
break
if (
not publish_states & PluginStates.HasError
and not result["success"]
):
new_flag_states[PluginStates.HasError] = True
if not publish_states & PluginStates.IsCompatible:
new_flag_states[PluginStates.IsCompatible] = True
item.setData(new_flag_states, Roles.PublishFlagsRole)
records = item.data(Roles.LogRecordsRole) or []
records.extend(new_records)
item.setData(records, Roles.LogRecordsRole)
return item
def update_compatibility(self):
context = self.controller.context
families = util.collect_families_from_instances(context, True)
for plugin_item in self.plugin_items.values():
publish_states = plugin_item.data(Roles.PublishFlagsRole)
if (
publish_states & PluginStates.WasProcessed
or publish_states & PluginStates.WasSkipped
):
continue
is_compatible = False
# A plugin should always show if it has processed.
if plugin_item.plugin.__instanceEnabled__:
compatible_instances = pyblish.logic.instances_by_plugin(
context, plugin_item.plugin
)
for instance in context:
if not instance.data.get("publish"):
continue
if instance in compatible_instances:
is_compatible = True
break
else:
plugins = pyblish.logic.plugins_by_families(
[plugin_item.plugin], families
)
if plugins:
is_compatible = True
current_is_compatible = publish_states & PluginStates.IsCompatible
if (
(is_compatible and not current_is_compatible)
or (not is_compatible and current_is_compatible)
):
new_flag = {
PluginStates.IsCompatible: is_compatible
}
plugin_item.setData(new_flag, Roles.PublishFlagsRole)
class PluginFilterProxy(QtCore.QSortFilterProxyModel):
def filterAcceptsRow(self, source_row, source_parent):
index = self.sourceModel().index(source_row, 0, source_parent)
item_type = index.data(Roles.TypeRole)
if item_type != PluginType:
return True
publish_states = index.data(Roles.PublishFlagsRole)
if (
publish_states & PluginStates.WasSkipped
or not publish_states & PluginStates.IsCompatible
):
return False
return True
class InstanceItem(QtGui.QStandardItem):
"""Instance item implementation."""
def __init__(self, instance):
super(InstanceItem, self).__init__()
self.instance = instance
self.is_context = False
publish_states = getattr(instance, "_publish_states", 0)
if publish_states & InstanceStates.ContextType:
self.is_context = True
instance._publish_states = publish_states
instance._logs = []
instance.optional = getattr(instance, "optional", True)
instance.data["publish"] = instance.data.get("publish", True)
instance.data["label"] = (
instance.data.get("label")
or getattr(instance, "label", None)
or instance.data["name"]
)
family = self.data(Roles.FamiliesRole)[0]
self.setData(
"{}.{}".format(family, self.instance.data["name"]),
Roles.ObjectUIdRole
)
def flags(self):
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
def type(self):
return InstanceType
def data(self, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if settings.UseLabel:
return self.instance.data["label"]
return self.instance.data["name"]
if role == QtCore.Qt.DecorationRole:
icon_name = self.instance.data.get("icon") or "file"
return QAwesomeTextIconFactory.icon(icon_name)
if role == Roles.TypeRole:
return self.type()
if role == Roles.ObjectIdRole:
return self.instance.id
if role == Roles.FamiliesRole:
if self.is_context:
return ["Context"]
families = []
family = self.instance.data.get("family")
if family:
families.append(family)
_families = self.instance.data.get("families") or []
for _family in _families:
if _family not in families:
families.append(_family)
return families
if role == Roles.IsOptionalRole:
return self.instance.optional
if role == QtCore.Qt.CheckStateRole:
return self.instance.data["publish"]
if role == Roles.PublishFlagsRole:
return self.instance._publish_states
if role == Roles.LogRecordsRole:
return self.instance._logs
return super(InstanceItem, self).data(role)
def setData(self, value, role=(QtCore.Qt.UserRole + 1)):
if role == QtCore.Qt.CheckStateRole:
if not self.data(Roles.IsEnabledRole):
return
self.instance.data["publish"] = value
self.emitDataChanged()
return
if role == Roles.IsEnabledRole:
if not self.instance.optional:
return
if role == Roles.PublishFlagsRole:
if isinstance(value, list):
_value = self.instance._publish_states
for flag in value:
_value |= flag
value = _value
elif isinstance(value, dict):
_value = self.instance._publish_states
for flag, _bool in value.items():
if _bool is True:
_value |= flag
elif _value & flag:
_value ^= flag
value = _value
if value & InstanceStates.HasWarning:
if self.parent():
self.parent().setData(
{GroupStates.HasWarning: True},
Roles.PublishFlagsRole
)
if value & InstanceStates.HasError:
if self.parent():
self.parent().setData(
{GroupStates.HasError: True},
Roles.PublishFlagsRole
)
self.instance._publish_states = value
self.emitDataChanged()
return
if role == Roles.LogRecordsRole:
self.instance._logs = value
self.emitDataChanged()
return
return super(InstanceItem, self).setData(value, role)
class InstanceModel(QtGui.QStandardItemModel):
group_created = QtCore.Signal(QtCore.QModelIndex)
def __init__(self, controller, *args, **kwargs):
super(InstanceModel, self).__init__(*args, **kwargs)
self.controller = controller
self.checkstates = {}
self.group_items = {}
self.instance_items = {}
def reset(self):
self.group_items = {}
self.instance_items = {}
self.clear()
def append(self, instance):
new_item = InstanceItem(instance)
if new_item.is_context:
self.appendRow(new_item)
else:
families = new_item.data(Roles.FamiliesRole)
group_item = self.group_items.get(families[0])
if not group_item:
group_item = GroupItem(families[0])
self.appendRow(group_item)
self.group_items[families[0]] = group_item
self.group_created.emit(group_item.index())
group_item.appendRow(new_item)
instance_id = instance.id
self.instance_items[instance_id] = new_item
def remove(self, instance_id):
instance_item = self.instance_items.pop(instance_id)
parent_item = instance_item.parent()
parent_item.removeRow(instance_item.row())
if parent_item.rowCount():
return
self.group_items.pop(parent_item.data(QtCore.Qt.DisplayRole))
self.removeRow(parent_item.row())
def store_checkstates(self):
self.checkstates.clear()
for instance_item in self.instance_items.values():
if not instance_item.instance.optional:
continue
uid = instance_item.data(Roles.ObjectUIdRole)
self.checkstates[uid] = instance_item.data(
QtCore.Qt.CheckStateRole
)
def restore_checkstates(self):
for instance_item in self.instance_items.values():
if not instance_item.instance.optional:
continue
uid = instance_item.data(Roles.ObjectUIdRole)
state = self.checkstates.get(uid)
if state is not None:
instance_item.setData(state, QtCore.Qt.CheckStateRole)
def update_with_result(self, result):
instance = result["instance"]
if instance is None:
instance_id = self.controller.context.id
else:
instance_id = instance.id
item = self.instance_items.get(instance_id)
if not item:
return
new_flag_states = {
InstanceStates.InProgress: False
}
publish_states = item.data(Roles.PublishFlagsRole)
has_warning = publish_states & InstanceStates.HasWarning
new_records = result.get("records") or []
if not has_warning:
for record in new_records:
level_no = record.get("levelno")
if level_no and level_no >= 30:
new_flag_states[InstanceStates.HasWarning] = True
break
if (
not publish_states & InstanceStates.HasError
and not result["success"]
):
new_flag_states[InstanceStates.HasError] = True
item.setData(new_flag_states, Roles.PublishFlagsRole)
records = item.data(Roles.LogRecordsRole) or []
records.extend(new_records)
item.setData(records, Roles.LogRecordsRole)
return item
def update_compatibility(self, context, instances):
families = util.collect_families_from_instances(context, True)
for plugin_item in self.plugin_items.values():
publish_states = plugin_item.data(Roles.PublishFlagsRole)
if (
publish_states & PluginStates.WasProcessed
or publish_states & PluginStates.WasSkipped
):
continue
is_compatible = False
# A plugin should always show if it has processed.
if plugin_item.plugin.__instanceEnabled__:
compatibleInstances = pyblish.logic.instances_by_plugin(
context, plugin_item.plugin
)
for instance in instances:
if not instance.data.get("publish"):
continue
if instance in compatibleInstances:
is_compatible = True
break
else:
plugins = pyblish.logic.plugins_by_families(
[plugin_item.plugin], families
)
if plugins:
is_compatible = True
current_is_compatible = publish_states & PluginStates.IsCompatible
if (
(is_compatible and not current_is_compatible)
or (not is_compatible and current_is_compatible)
):
plugin_item.setData(
{PluginStates.IsCompatible: is_compatible},
Roles.PublishFlagsRole
)
class InstanceSortProxy(QtCore.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(InstanceSortProxy, self).__init__(*args, **kwargs)
# Do not care about lower/upper case
self.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
def lessThan(self, x_index, y_index):
x_type = x_index.data(Roles.TypeRole)
y_type = y_index.data(Roles.TypeRole)
if x_type != y_type:
if x_type == GroupType:
return False
return True
return super(InstanceSortProxy, self).lessThan(x_index, y_index)
class TerminalDetailItem(QtGui.QStandardItem):
key_label_record_map = (
("instance", "Instance"),
("msg", "Message"),
("name", "Plugin"),
("pathname", "Path"),
("lineno", "Line"),
("traceback", "Traceback"),
("levelname", "Level"),
("threadName", "Thread"),
("msecs", "Millis")
)
def __init__(self, record_item):
self.record_item = record_item
self.msg = None
msg = record_item.get("msg")
if msg is None:
msg = record_item["label"].split("\n")[0]
super(TerminalDetailItem, self).__init__(msg)
def data(self, role=QtCore.Qt.DisplayRole):
if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
if self.msg is None:
self.msg = self.compute_detail_text(self.record_item)
return self.msg
return super(TerminalDetailItem, self).data(role)
def compute_detail_text(self, item_data):
if item_data["type"] == "info":
return item_data["label"]
html_text = ""
for key, title in self.key_label_record_map:
if key not in item_data:
continue
value = item_data[key]
text = (
str(value)
.replace("<", "&#60;")
.replace(">", "&#62;")
.replace('\n', '<br/>')
.replace(' ', '&nbsp;')
)
title_tag = (
'<span style=\" font-size:8pt; font-weight:600;'
# ' background-color:#bbb; color:#333;\" >{}:</span> '
' color:#fff;\" >{}:</span> '
).format(title)
html_text += (
'<tr><td width="100%" align=left>{}</td></tr>'
'<tr><td width="100%">{}</td></tr>'
).format(title_tag, text)
html_text = '<table width="100%" cellspacing="3">{}</table>'.format(
html_text
)
return html_text
class TerminalModel(QtGui.QStandardItemModel):
item_icon_name = {
"info": "fa.info",
"record": "fa.circle",
"error": "fa.exclamation-triangle",
}
item_icon_colors = {
"info": "#ffffff",
"error": "#ff4a4a",
"log_debug": "#ff66e8",
"log_info": "#66abff",
"log_warning": "#ffba66",
"log_error": "#ff4d58",
"log_critical": "#ff4f75",
None: "#333333"
}
level_to_record = (
(10, "log_debug"),
(20, "log_info"),
(30, "log_warning"),
(40, "log_error"),
(50, "log_critical")
)
def __init__(self, *args, **kwargs):
super(TerminalModel, self).__init__(*args, **kwargs)
self.reset()
def reset(self):
self.clear()
def prepare_records(self, result, suspend_logs):
prepared_records = []
instance_name = None
instance = result["instance"]
if instance is not None:
instance_name = instance.data["name"]
if not suspend_logs:
for record in result.get("records") or []:
if isinstance(record, dict):
record_item = record
else:
record_item = {
"label": text_type(record.msg),
"type": "record",
"levelno": record.levelno,
"threadName": record.threadName,
"name": record.name,
"filename": record.filename,
"pathname": record.pathname,
"lineno": record.lineno,
"msg": text_type(record.msg),
"msecs": record.msecs,
"levelname": record.levelname
}
if instance_name is not None:
record_item["instance"] = instance_name
prepared_records.append(record_item)
error = result.get("error")
if error:
fname, line_no, func, exc = error.traceback
error_item = {
"label": str(error),
"type": "error",
"filename": str(fname),
"lineno": str(line_no),
"func": str(func),
"traceback": error.formatted_traceback,
}
if instance_name is not None:
error_item["instance"] = instance_name
prepared_records.append(error_item)
return prepared_records
def append(self, record_items):
all_record_items = []
for record_item in record_items:
record_type = record_item["type"]
# Add error message to detail
if record_type == "error":
record_item["msg"] = record_item["label"]
terminal_item_type = None
if record_type == "record":
for level, _type in self.level_to_record:
if level > record_item["levelno"]:
break
terminal_item_type = _type
else:
terminal_item_type = record_type
icon_color = self.item_icon_colors.get(terminal_item_type)
icon_name = self.item_icon_name.get(record_type)
top_item_icon = None
if icon_color and icon_name:
top_item_icon = QAwesomeIconFactory.icon(icon_name, icon_color)
label = record_item["label"].split("\n")[0]
top_item = QtGui.QStandardItem()
all_record_items.append(top_item)
detail_item = TerminalDetailItem(record_item)
top_item.appendRow(detail_item)
top_item.setData(TerminalLabelType, Roles.TypeRole)
top_item.setData(terminal_item_type, Roles.TerminalItemTypeRole)
top_item.setData(label, QtCore.Qt.DisplayRole)
top_item.setFlags(
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
)
if top_item_icon:
top_item.setData(top_item_icon, QtCore.Qt.DecorationRole)
detail_item.setData(TerminalDetailType, Roles.TypeRole)
self.invisibleRootItem().appendRows(all_record_items)
def update_with_result(self, result):
self.append(result["records"])
class TerminalProxy(QtCore.QSortFilterProxyModel):
filter_buttons_checks = {
"info": settings.TerminalFilters.get("info", True),
"log_debug": settings.TerminalFilters.get("log_debug", True),
"log_info": settings.TerminalFilters.get("log_info", True),
"log_warning": settings.TerminalFilters.get("log_warning", True),
"log_error": settings.TerminalFilters.get("log_error", True),
"log_critical": settings.TerminalFilters.get("log_critical", True),
"error": settings.TerminalFilters.get("error", True)
}
instances = []
def __init__(self, view, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
self.__class__.instances.append(self)
# Store parent because by own `QSortFilterProxyModel` has `parent`
# method not returning parent QObject in PySide and PyQt4
self.view = view
@classmethod
def change_filter(cls, name, value):
cls.filter_buttons_checks[name] = value
for instance in cls.instances:
try:
instance.invalidate()
if instance.view:
instance.view.updateGeometry()
except RuntimeError:
# C++ Object was deleted
cls.instances.remove(instance)
def filterAcceptsRow(self, source_row, source_parent):
index = self.sourceModel().index(source_row, 0, source_parent)
item_type = index.data(Roles.TypeRole)
if not item_type == TerminalLabelType:
return True
terminal_item_type = index.data(Roles.TerminalItemTypeRole)
return self.__class__.filter_buttons_checks.get(
terminal_item_type, True
)