mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
reworked card view for easier maintanance of widget updates
This commit is contained in:
parent
d8392a2133
commit
6bc3e5130e
1 changed files with 326 additions and 318 deletions
|
|
@ -23,7 +23,7 @@ from __future__ import annotations
|
|||
|
||||
import re
|
||||
import collections
|
||||
from typing import Dict
|
||||
from typing import Optional
|
||||
|
||||
from qtpy import QtWidgets, QtCore
|
||||
|
||||
|
|
@ -87,7 +87,6 @@ class BaseGroupWidget(QtWidgets.QWidget):
|
|||
self._group = group_name
|
||||
|
||||
self._widgets_by_id = {}
|
||||
self._ordered_item_ids = []
|
||||
|
||||
self._label_widget = label_widget
|
||||
self._content_layout = layout
|
||||
|
|
@ -102,48 +101,25 @@ class BaseGroupWidget(QtWidgets.QWidget):
|
|||
|
||||
return self._group
|
||||
|
||||
def get_widget_by_item_id(self, item_id):
|
||||
"""Get instance widget by its id."""
|
||||
def set_widgets(
|
||||
self,
|
||||
widgets_by_id: dict[str, QtWidgets.QWidget],
|
||||
ordered_ids: list[str],
|
||||
) -> None:
|
||||
self._remove_all_except(set(self._widgets_by_id))
|
||||
idx = 1
|
||||
for item_id in ordered_ids:
|
||||
widget = widgets_by_id[item_id]
|
||||
self._content_layout.insertWidget(idx, widget)
|
||||
self._widgets_by_id[item_id] = widget
|
||||
idx += 1
|
||||
|
||||
return self._widgets_by_id.get(item_id)
|
||||
|
||||
def get_selected_item_ids(self):
|
||||
"""Selected instance ids.
|
||||
|
||||
Returns:
|
||||
Set[str]: Instance ids that are selected.
|
||||
"""
|
||||
|
||||
return {
|
||||
instance_id
|
||||
for instance_id, widget in self._widgets_by_id.items()
|
||||
if widget.is_selected
|
||||
}
|
||||
|
||||
def get_selected_widgets(self):
|
||||
"""Access to widgets marked as selected.
|
||||
|
||||
Returns:
|
||||
List[InstanceCardWidget]: Instance widgets that are selected.
|
||||
"""
|
||||
|
||||
return [
|
||||
widget
|
||||
for instance_id, widget in self._widgets_by_id.items()
|
||||
if widget.is_selected
|
||||
]
|
||||
|
||||
def get_ordered_widgets(self):
|
||||
"""Get instance ids in order as are shown in ui.
|
||||
|
||||
Returns:
|
||||
List[str]: Instance ids.
|
||||
"""
|
||||
|
||||
return [
|
||||
self._widgets_by_id[instance_id]
|
||||
for instance_id in self._ordered_item_ids
|
||||
]
|
||||
def take_widgets(self, widget_ids: set[str]):
|
||||
for widget_id in widget_ids:
|
||||
widget = self._widgets_by_id.pop(widget_id)
|
||||
index = self._content_layout.indexOf(widget)
|
||||
if index >= 0:
|
||||
self._content_layout.takeAt(index)
|
||||
|
||||
def _remove_all_except(self, item_ids):
|
||||
item_ids = set(item_ids)
|
||||
|
|
@ -160,149 +136,6 @@ class BaseGroupWidget(QtWidgets.QWidget):
|
|||
self._content_layout.removeWidget(widget)
|
||||
widget.deleteLater()
|
||||
|
||||
def _update_ordered_item_ids(self):
|
||||
ordered_item_ids = []
|
||||
for idx in range(self._content_layout.count()):
|
||||
if idx > 0:
|
||||
item = self._content_layout.itemAt(idx)
|
||||
widget = item.widget()
|
||||
if widget is not None:
|
||||
ordered_item_ids.append(widget.id)
|
||||
|
||||
self._ordered_item_ids = ordered_item_ids
|
||||
|
||||
def _on_widget_selection(self, instance_id, group_id, selection_type):
|
||||
self.selected.emit(instance_id, group_id, selection_type)
|
||||
|
||||
def set_active_toggle_enabled(self, enabled):
|
||||
for widget in self._widgets_by_id.values():
|
||||
if isinstance(widget, InstanceCardWidget):
|
||||
widget.set_active_toggle_enabled(enabled)
|
||||
|
||||
|
||||
class ConvertorItemsGroupWidget(BaseGroupWidget):
|
||||
def update_items(self, items_by_id):
|
||||
items_by_label = collections.defaultdict(list)
|
||||
for item in items_by_id.values():
|
||||
items_by_label[item.label].append(item)
|
||||
|
||||
# Remove instance widgets that are not in passed instances
|
||||
self._remove_all_except(items_by_id.keys())
|
||||
|
||||
# Sort instances by product name
|
||||
sorted_labels = list(sorted(items_by_label.keys()))
|
||||
|
||||
# Add new instances to widget
|
||||
widget_idx = 1
|
||||
for label in sorted_labels:
|
||||
for item in items_by_label[label]:
|
||||
if item.id in self._widgets_by_id:
|
||||
widget = self._widgets_by_id[item.id]
|
||||
widget.update_item(item)
|
||||
else:
|
||||
widget = ConvertorItemCardWidget(item, self)
|
||||
widget.selected.connect(self._on_widget_selection)
|
||||
widget.double_clicked.connect(self.double_clicked)
|
||||
self._widgets_by_id[item.id] = widget
|
||||
self._content_layout.insertWidget(widget_idx, widget)
|
||||
widget_idx += 1
|
||||
|
||||
self._update_ordered_item_ids()
|
||||
|
||||
|
||||
class InstanceGroupWidget(BaseGroupWidget):
|
||||
"""Widget wrapping instances under group."""
|
||||
|
||||
active_changed = QtCore.Signal(str, str, bool)
|
||||
|
||||
def __init__(self, group_icons, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self._group_icons = group_icons
|
||||
|
||||
def update_icons(self, group_icons):
|
||||
self._group_icons = group_icons
|
||||
|
||||
def update_instance_values(
|
||||
self,
|
||||
context_info_by_id,
|
||||
instance_items_by_id,
|
||||
instance_ids,
|
||||
parent_is_active_by_id,
|
||||
):
|
||||
"""Trigger update on instance widgets."""
|
||||
|
||||
for instance_id, widget in self._widgets_by_id.items():
|
||||
if instance_ids is not None and instance_id not in instance_ids:
|
||||
continue
|
||||
widget.update_instance(
|
||||
instance_items_by_id[instance_id],
|
||||
context_info_by_id[instance_id],
|
||||
parent_is_active_by_id[instance_id],
|
||||
)
|
||||
|
||||
def update_instances(
|
||||
self,
|
||||
instances: list[InstanceItem],
|
||||
context_info_by_id: dict[str, InstanceContextInfo],
|
||||
parent_active_by_id: dict[str, bool]
|
||||
):
|
||||
"""Update instances for the group.
|
||||
|
||||
Args:
|
||||
instances (list[InstanceItem]): List of instances in
|
||||
CreateContext.
|
||||
context_info_by_id (dict[str, InstanceContextInfo]): Instance
|
||||
context info by instance id.
|
||||
parent_active_by_id (dict[str, bool]): Instance has active parent.
|
||||
|
||||
"""
|
||||
# Store instances by id and by product name
|
||||
instances_by_id = {}
|
||||
instances_by_product_name = collections.defaultdict(list)
|
||||
for instance in instances:
|
||||
instances_by_id[instance.id] = instance
|
||||
product_name = instance.product_name
|
||||
instances_by_product_name[product_name].append(instance)
|
||||
|
||||
# Remove instance widgets that are not in passed instances
|
||||
self._remove_all_except(instances_by_id.keys())
|
||||
|
||||
# Sort instances by product name
|
||||
sorted_product_names = list(sorted(instances_by_product_name.keys()))
|
||||
|
||||
# Add new instances to widget
|
||||
widget_idx = 1
|
||||
for product_names in sorted_product_names:
|
||||
for instance in instances_by_product_name[product_names]:
|
||||
context_info = context_info_by_id[instance.id]
|
||||
parent_is_active = parent_active_by_id[instance.id]
|
||||
if instance.id in self._widgets_by_id:
|
||||
widget = self._widgets_by_id[instance.id]
|
||||
widget.update_instance(
|
||||
instance, context_info, parent_is_active
|
||||
)
|
||||
else:
|
||||
group_icon = self._group_icons[instance.creator_identifier]
|
||||
widget = InstanceCardWidget(
|
||||
instance,
|
||||
context_info,
|
||||
parent_is_active,
|
||||
group_icon,
|
||||
self
|
||||
)
|
||||
widget.selected.connect(self._on_widget_selection)
|
||||
widget.active_changed.connect(self._on_active_changed)
|
||||
widget.double_clicked.connect(self.double_clicked)
|
||||
self._widgets_by_id[instance.id] = widget
|
||||
self._content_layout.insertWidget(widget_idx, widget)
|
||||
widget_idx += 1
|
||||
|
||||
self._update_ordered_item_ids()
|
||||
|
||||
def _on_active_changed(self, instance_id, value):
|
||||
self.active_changed.emit(self.group_name, instance_id, value)
|
||||
|
||||
|
||||
class CardWidget(BaseClickableFrame):
|
||||
"""Clickable card used as bigger button."""
|
||||
|
|
@ -423,6 +256,10 @@ class ConvertorItemCardWidget(CardWidget):
|
|||
self._icon_widget = icon_widget
|
||||
self._label_widget = label_widget
|
||||
|
||||
def update_item(self, item):
|
||||
self._id = item.id
|
||||
self.identifier = item.identifier
|
||||
|
||||
|
||||
class InstanceCardWidget(CardWidget):
|
||||
"""Card widget representing instance."""
|
||||
|
|
@ -433,7 +270,7 @@ class InstanceCardWidget(CardWidget):
|
|||
self,
|
||||
instance,
|
||||
context_info,
|
||||
parent_is_active: bool,
|
||||
is_parent_active: bool,
|
||||
group_icon,
|
||||
parent: BaseGroupWidget,
|
||||
):
|
||||
|
|
@ -444,7 +281,7 @@ class InstanceCardWidget(CardWidget):
|
|||
self._id = instance.id
|
||||
self._group_identifier = instance.group_label
|
||||
self._group_icon = group_icon
|
||||
self._parent_is_active = parent_is_active
|
||||
self._is_parent_active = is_parent_active
|
||||
self._toggle_is_enabled = True
|
||||
|
||||
self._last_product_name = None
|
||||
|
|
@ -499,18 +336,26 @@ class InstanceCardWidget(CardWidget):
|
|||
self._active_checkbox = active_checkbox
|
||||
self._expand_btn = expand_btn
|
||||
|
||||
self._update_instance_values(context_info, parent_is_active)
|
||||
self._update_instance_values(context_info, is_parent_active)
|
||||
|
||||
def set_active_toggle_enabled(self, enabled):
|
||||
def set_active_toggle_enabled(self, enabled: bool) -> None:
|
||||
if self._toggle_is_enabled is enabled:
|
||||
return
|
||||
self._toggle_is_enabled = enabled
|
||||
self._update_checkbox_state()
|
||||
|
||||
@property
|
||||
def is_active(self):
|
||||
def is_active(self) -> bool:
|
||||
return self._active_checkbox.isChecked()
|
||||
|
||||
def is_parent_active(self) -> bool:
|
||||
return self._is_parent_active
|
||||
|
||||
def set_parent_active(self, is_active: bool) -> None:
|
||||
if self._is_parent_active is is_active:
|
||||
return
|
||||
self._is_parent_active = is_active
|
||||
self._update_checkbox_state()
|
||||
|
||||
def is_checkbox_enabled(self) -> bool:
|
||||
"""Checkbox can be changed by user."""
|
||||
return (
|
||||
|
|
@ -518,10 +363,10 @@ class InstanceCardWidget(CardWidget):
|
|||
and not self.instance.is_mandatory
|
||||
)
|
||||
|
||||
def update_instance(self, instance, context_info, parent_is_active):
|
||||
def update_instance(self, instance, context_info, is_parent_active):
|
||||
"""Update instance object and update UI."""
|
||||
self.instance = instance
|
||||
self._update_instance_values(context_info, parent_is_active)
|
||||
self._update_instance_values(context_info, is_parent_active)
|
||||
|
||||
def _validate_context(self, context_info):
|
||||
valid = context_info.is_valid
|
||||
|
|
@ -560,9 +405,9 @@ class InstanceCardWidget(CardWidget):
|
|||
QtCore.Qt.NoTextInteraction
|
||||
)
|
||||
|
||||
def _update_instance_values(self, context_info, parent_is_active):
|
||||
def _update_instance_values(self, context_info, is_parent_active):
|
||||
"""Update instance data"""
|
||||
self._parent_is_active = parent_is_active
|
||||
self._is_parent_active = is_parent_active
|
||||
self._update_product_name()
|
||||
self._update_checkbox_state()
|
||||
self._validate_context(context_info)
|
||||
|
|
@ -587,7 +432,7 @@ class InstanceCardWidget(CardWidget):
|
|||
def _used_parent_active(self) -> bool:
|
||||
parent_enabled = True
|
||||
if self.instance.parent_flags & ParentFlags.share_active:
|
||||
parent_enabled = self._parent_is_active
|
||||
parent_enabled = self._is_parent_active
|
||||
return parent_enabled
|
||||
|
||||
def _set_expanded(self, expanded=None):
|
||||
|
|
@ -654,11 +499,20 @@ class InstanceCardView(AbstractInstanceView):
|
|||
self._content_layout = content_layout
|
||||
self._content_widget = content_widget
|
||||
|
||||
self._context_widget = None
|
||||
self._convertor_items_group = None
|
||||
self._active_toggle_enabled = True
|
||||
self._widgets_by_group: Dict[str, InstanceGroupWidget] = {}
|
||||
self._active_toggle_enabled: bool = True
|
||||
self._convertors_group: Optional[BaseGroupWidget] = None
|
||||
self._convertor_widgets_by_id: dict[str, ConvertorItemCardWidget] = {}
|
||||
self._convertor_ids: list[str] = []
|
||||
|
||||
self._group_name_by_instance_id: dict[str, str] = {}
|
||||
self._instance_ids_by_group_name: dict[str, list[str]] = (
|
||||
collections.defaultdict(list)
|
||||
)
|
||||
self._ordered_groups = []
|
||||
self._group_icons = {}
|
||||
self._context_widget: Optional[ContextCardWidget] = None
|
||||
self._widgets_by_id: dict[str, InstanceCardWidget] = {}
|
||||
self._widgets_by_group: dict[str, BaseGroupWidget] = {}
|
||||
|
||||
self._instance_ids_by_parent_id = collections.defaultdict(set)
|
||||
|
||||
|
|
@ -694,7 +548,7 @@ class InstanceCardView(AbstractInstanceView):
|
|||
continue
|
||||
|
||||
instance_id = widget.id
|
||||
is_active = widget.is_active
|
||||
is_active = widget.is_active()
|
||||
if value == -1:
|
||||
active_state_by_id[instance_id] = not is_active
|
||||
continue
|
||||
|
|
@ -731,12 +585,17 @@ class InstanceCardView(AbstractInstanceView):
|
|||
):
|
||||
output.append(self._context_widget)
|
||||
|
||||
if self._convertor_items_group is not None:
|
||||
output.extend(self._convertor_items_group.get_selected_widgets())
|
||||
output.extend(
|
||||
widget
|
||||
for widget in self._convertor_widgets_by_id.values()
|
||||
if widget.is_selected
|
||||
)
|
||||
|
||||
for group_widget in self._widgets_by_group.values():
|
||||
for widget in group_widget.get_selected_widgets():
|
||||
output.append(widget)
|
||||
output.extend(
|
||||
widget
|
||||
for widget in self._widgets_by_id.values()
|
||||
if widget.is_selected
|
||||
)
|
||||
return output
|
||||
|
||||
def _get_selected_instance_ids(self):
|
||||
|
|
@ -747,11 +606,17 @@ class InstanceCardView(AbstractInstanceView):
|
|||
):
|
||||
output.append(CONTEXT_ID)
|
||||
|
||||
if self._convertor_items_group is not None:
|
||||
output.extend(self._convertor_items_group.get_selected_item_ids())
|
||||
output.extend(
|
||||
conv_id
|
||||
for conv_id, widget in self._widgets_by_id.items()
|
||||
if widget.is_selected
|
||||
)
|
||||
|
||||
for group_widget in self._widgets_by_group.values():
|
||||
output.extend(group_widget.get_selected_item_ids())
|
||||
output.extend(
|
||||
widget.id
|
||||
for instance_id, widget in self._widgets_by_id.items()
|
||||
if widget.is_selected
|
||||
)
|
||||
return output
|
||||
|
||||
def refresh(self):
|
||||
|
|
@ -759,13 +624,14 @@ class InstanceCardView(AbstractInstanceView):
|
|||
|
||||
self._make_sure_context_widget_exists()
|
||||
|
||||
self._update_convertor_items_group()
|
||||
self._update_convertors_group()
|
||||
|
||||
context_info_by_id = self._controller.get_instances_context_info()
|
||||
|
||||
# Prepare instances by group and identifiers by group
|
||||
instances_by_group = collections.defaultdict(list)
|
||||
identifiers_by_group = collections.defaultdict(set)
|
||||
identifiers: set[str] = set()
|
||||
instances_by_id = {}
|
||||
instance_ids_by_parent_id = collections.defaultdict(set)
|
||||
instance_items = self._controller.get_instance_items()
|
||||
|
|
@ -775,6 +641,7 @@ class InstanceCardView(AbstractInstanceView):
|
|||
identifiers_by_group[group_name].add(
|
||||
instance.creator_identifier
|
||||
)
|
||||
identifiers.add(instance.creator_identifier)
|
||||
instances_by_id[instance.id] = instance
|
||||
instance_ids_by_parent_id[instance.parent_instance_id].add(
|
||||
instance.id
|
||||
|
|
@ -787,28 +654,67 @@ class InstanceCardView(AbstractInstanceView):
|
|||
_queue = collections.deque()
|
||||
_queue.append((None, True))
|
||||
while _queue:
|
||||
parent_id, parent_is_active = _queue.popleft()
|
||||
parent_id, is_parent_active = _queue.popleft()
|
||||
for instance_id in instance_ids_by_parent_id[parent_id]:
|
||||
instance_item = instances_by_id[instance_id]
|
||||
is_active = instance_item.is_active
|
||||
if (
|
||||
not parent_is_active
|
||||
not is_parent_active
|
||||
and instance_item.parent_flags & ParentFlags.share_active
|
||||
):
|
||||
is_active = False
|
||||
|
||||
parent_active_by_id[instance_id] = parent_is_active
|
||||
parent_active_by_id[instance_id] = is_parent_active
|
||||
_queue.append(
|
||||
(instance_id, is_active)
|
||||
)
|
||||
|
||||
self._instance_ids_by_parent_id = instance_ids_by_parent_id
|
||||
# Remove groups that were not found in passed instances
|
||||
groups_to_remove = (
|
||||
set(self._widgets_by_group) - set(instances_by_group)
|
||||
)
|
||||
|
||||
# Remove groups that were not found in apassed instances
|
||||
for group_name in tuple(self._widgets_by_group.keys()):
|
||||
if group_name in instances_by_group:
|
||||
continue
|
||||
# Sort groups
|
||||
sorted_group_names = list(sorted(instances_by_group.keys()))
|
||||
|
||||
# Keep track of widget indexes
|
||||
# - we start with 1 because Context item as at the top
|
||||
widget_idx = 1
|
||||
if self._convertors_group is not None:
|
||||
widget_idx += 1
|
||||
|
||||
group_by_instance_id = {}
|
||||
instance_ids_by_group_name = collections.defaultdict(list)
|
||||
group_icons = {
|
||||
identifier: self._controller.get_creator_icon(identifier)
|
||||
for identifier in identifiers
|
||||
}
|
||||
for group_name in sorted_group_names:
|
||||
if group_name not in self._widgets_by_group:
|
||||
group_widget = BaseGroupWidget(
|
||||
group_name, self._content_widget
|
||||
)
|
||||
group_widget.double_clicked.connect(self.double_clicked)
|
||||
self._content_layout.insertWidget(widget_idx, group_widget)
|
||||
self._widgets_by_group[group_name] = group_widget
|
||||
|
||||
widget_idx += 1
|
||||
|
||||
instances = instances_by_group[group_name]
|
||||
for instance in instances:
|
||||
group_by_instance_id[instance.id] = group_name
|
||||
instance_ids_by_group_name[group_name].append(instance.id)
|
||||
|
||||
self._update_instances(
|
||||
group_name,
|
||||
instances,
|
||||
context_info_by_id,
|
||||
parent_active_by_id,
|
||||
group_icons,
|
||||
)
|
||||
|
||||
# Remove empty groups
|
||||
for group_name in groups_to_remove:
|
||||
widget = self._widgets_by_group.pop(group_name)
|
||||
widget.setVisible(False)
|
||||
self._content_layout.removeWidget(widget)
|
||||
|
|
@ -817,63 +723,85 @@ class InstanceCardView(AbstractInstanceView):
|
|||
if group_name in self._explicitly_selected_groups:
|
||||
self._explicitly_selected_groups.remove(group_name)
|
||||
|
||||
# Sort groups
|
||||
sorted_group_names = list(sorted(instances_by_group.keys()))
|
||||
|
||||
# Keep track of widget indexes
|
||||
# - we start with 1 because Context item as at the top
|
||||
widget_idx = 1
|
||||
if self._convertor_items_group is not None:
|
||||
widget_idx += 1
|
||||
|
||||
for group_name in sorted_group_names:
|
||||
group_icons = {
|
||||
identifier: self._controller.get_creator_icon(identifier)
|
||||
for identifier in identifiers_by_group[group_name]
|
||||
}
|
||||
if group_name in self._widgets_by_group:
|
||||
group_widget = self._widgets_by_group[group_name]
|
||||
group_widget.update_icons(group_icons)
|
||||
|
||||
else:
|
||||
group_widget = InstanceGroupWidget(
|
||||
group_icons, group_name, self._content_widget
|
||||
)
|
||||
group_widget.active_changed.connect(self._on_active_changed)
|
||||
group_widget.selected.connect(self._on_widget_selection)
|
||||
group_widget.double_clicked.connect(self.double_clicked)
|
||||
self._content_layout.insertWidget(widget_idx, group_widget)
|
||||
self._widgets_by_group[group_name] = group_widget
|
||||
|
||||
widget_idx += 1
|
||||
group_widget.update_instances(
|
||||
instances_by_group[group_name],
|
||||
context_info_by_id,
|
||||
parent_active_by_id
|
||||
)
|
||||
group_widget.set_active_toggle_enabled(
|
||||
self._active_toggle_enabled
|
||||
)
|
||||
|
||||
self._update_ordered_group_names()
|
||||
self._instance_ids_by_parent_id = instance_ids_by_parent_id
|
||||
self._group_name_by_instance_id = group_by_instance_id
|
||||
self._instance_ids_by_group_name = instance_ids_by_group_name
|
||||
self._ordered_groups = sorted_group_names
|
||||
|
||||
def has_items(self) -> bool:
|
||||
if self._convertor_items_group is not None:
|
||||
if self._convertors_group is not None:
|
||||
return True
|
||||
if self._widgets_by_group:
|
||||
if self._widgets_by_id:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _update_ordered_group_names(self):
|
||||
ordered_group_names = [CONTEXT_GROUP]
|
||||
for idx in range(self._content_layout.count()):
|
||||
if idx > 0:
|
||||
item = self._content_layout.itemAt(idx)
|
||||
group_widget = item.widget()
|
||||
if group_widget is not None:
|
||||
ordered_group_names.append(group_widget.group_name)
|
||||
def _update_instances(
|
||||
self,
|
||||
group_name: str,
|
||||
instances: list[InstanceItem],
|
||||
context_info_by_id: dict[str, InstanceContextInfo],
|
||||
parent_active_by_id: dict[str, bool],
|
||||
group_icons: dict[str, str],
|
||||
):
|
||||
"""Update instances for the group.
|
||||
|
||||
self._ordered_groups = ordered_group_names
|
||||
Args:
|
||||
instances (list[InstanceItem]): List of instances in
|
||||
CreateContext.
|
||||
context_info_by_id (dict[str, InstanceContextInfo]): Instance
|
||||
context info by instance id.
|
||||
parent_active_by_id (dict[str, bool]): Instance has active parent.
|
||||
|
||||
"""
|
||||
# Store instances by id and by product name
|
||||
group_widget: BaseGroupWidget = self._widgets_by_group[group_name]
|
||||
instances_by_id = {}
|
||||
instances_by_product_name = collections.defaultdict(list)
|
||||
for instance in instances:
|
||||
instances_by_id[instance.id] = instance
|
||||
product_name = instance.product_name
|
||||
instances_by_product_name[product_name].append(instance)
|
||||
|
||||
to_remove_ids = set(
|
||||
self._instance_ids_by_group_name[group_name]
|
||||
) - set(instances_by_id)
|
||||
group_widget.take_widgets(to_remove_ids)
|
||||
|
||||
# Sort instances by product name
|
||||
sorted_product_names = list(sorted(instances_by_product_name.keys()))
|
||||
|
||||
# Add new instances to widget
|
||||
ordered_ids = []
|
||||
widgets_by_id = {}
|
||||
for product_names in sorted_product_names:
|
||||
for instance in instances_by_product_name[product_names]:
|
||||
context_info = context_info_by_id[instance.id]
|
||||
is_parent_active = parent_active_by_id[instance.id]
|
||||
if instance.id in self._widgets_by_id:
|
||||
widget = self._widgets_by_id[instance.id]
|
||||
widget.update_instance(
|
||||
instance, context_info, is_parent_active
|
||||
)
|
||||
else:
|
||||
group_icon = group_icons[instance.creator_identifier]
|
||||
widget = InstanceCardWidget(
|
||||
instance,
|
||||
context_info,
|
||||
is_parent_active,
|
||||
group_icon,
|
||||
group_widget
|
||||
)
|
||||
widget.selected.connect(self._on_widget_selection)
|
||||
widget.active_changed.connect(self._on_active_changed)
|
||||
widget.double_clicked.connect(self.double_clicked)
|
||||
self._widgets_by_id[instance.id] = widget
|
||||
|
||||
ordered_ids.append(instance.id)
|
||||
widgets_by_id[instance.id] = widget
|
||||
|
||||
group_widget.set_widgets(widgets_by_id, ordered_ids)
|
||||
|
||||
return ordered_ids
|
||||
|
||||
def _make_sure_context_widget_exists(self):
|
||||
# Create context item if is not already existing
|
||||
|
|
@ -891,28 +819,65 @@ class InstanceCardView(AbstractInstanceView):
|
|||
self.selection_changed.emit()
|
||||
self._content_layout.insertWidget(0, widget)
|
||||
|
||||
def _update_convertor_items_group(self):
|
||||
def _update_convertors_group(self):
|
||||
convertor_items = self._controller.get_convertor_items()
|
||||
if not convertor_items and self._convertor_items_group is None:
|
||||
if not convertor_items and self._convertors_group is None:
|
||||
return
|
||||
|
||||
ids_to_remove = set(self._convertor_widgets_by_id) - set(
|
||||
convertor_items
|
||||
)
|
||||
if ids_to_remove:
|
||||
self._convertors_group.take_widgets(ids_to_remove)
|
||||
|
||||
for conv_id in ids_to_remove:
|
||||
widget = self._convertor_widgets_by_id.pop(conv_id)
|
||||
widget.setVisible(False)
|
||||
widget.deleteLater()
|
||||
|
||||
if not convertor_items:
|
||||
self._convertor_items_group.setVisible(False)
|
||||
self._content_layout.removeWidget(self._convertor_items_group)
|
||||
self._convertor_items_group.deleteLater()
|
||||
self._convertor_items_group = None
|
||||
self._convertors_group.setVisible(False)
|
||||
self._content_layout.removeWidget(self._convertors_group)
|
||||
self._convertors_group.deleteLater()
|
||||
self._convertors_group = None
|
||||
self._convertor_ids = []
|
||||
self._convertor_widgets_by_id = {}
|
||||
return
|
||||
|
||||
if self._convertor_items_group is None:
|
||||
group_widget = ConvertorItemsGroupWidget(
|
||||
if self._convertors_group is None:
|
||||
group_widget = BaseGroupWidget(
|
||||
CONVERTOR_ITEM_GROUP, self._content_widget
|
||||
)
|
||||
group_widget.selected.connect(self._on_widget_selection)
|
||||
group_widget.double_clicked.connect(self.double_clicked)
|
||||
self._content_layout.insertWidget(1, group_widget)
|
||||
self._convertor_items_group = group_widget
|
||||
self._convertors_group = group_widget
|
||||
|
||||
self._convertor_items_group.update_items(convertor_items)
|
||||
# TODO create convertor widgets
|
||||
items_by_label = collections.defaultdict(list)
|
||||
for item in convertor_items.values():
|
||||
items_by_label[item.label].append(item)
|
||||
|
||||
# Sort instances by product name
|
||||
sorted_labels = list(sorted(items_by_label.keys()))
|
||||
|
||||
# Add new instances to widget
|
||||
convertor_ids: list[str] = []
|
||||
widgets_by_id: dict[str, ConvertorItemCardWidget] = {}
|
||||
for label in sorted_labels:
|
||||
for item in items_by_label[label]:
|
||||
convertor_ids.append(item.id)
|
||||
if item.id in self._convertor_widgets_by_id:
|
||||
widget = self._convertor_widgets_by_id[item.id]
|
||||
widget.update_item(item)
|
||||
else:
|
||||
widget = ConvertorItemCardWidget(item, self)
|
||||
widget.selected.connect(self._on_widget_selection)
|
||||
widget.double_clicked.connect(self.double_clicked)
|
||||
self._convertor_widgets_by_id[item.id] = widget
|
||||
widgets_by_id[item.id] = widget
|
||||
|
||||
self._convertors_group.set_widgets(widgets_by_id, convertor_ids)
|
||||
self._convertor_ids = convertor_ids
|
||||
self._convertor_widgets_by_id = widgets_by_id
|
||||
|
||||
def refresh_instance_states(self, instance_ids=None):
|
||||
"""Trigger update of instances on group widgets."""
|
||||
|
|
@ -922,36 +887,57 @@ class InstanceCardView(AbstractInstanceView):
|
|||
instance_items_by_id = self._controller.get_instance_items_by_id(
|
||||
instance_ids
|
||||
)
|
||||
instance_ids = set(instance_items_by_id)
|
||||
instance_ids: set[str] = set(instance_items_by_id)
|
||||
available_ids: set[str] = set(instance_items_by_id)
|
||||
discarted_ids: set[str] = set()
|
||||
|
||||
parent_is_active_by_id = {
|
||||
instance_id: False
|
||||
for instance_id in instance_ids
|
||||
}
|
||||
|
||||
discarted_ids = set()
|
||||
_queue = collections.deque()
|
||||
_queue.append((None, True))
|
||||
_queue.append((set(self._instance_ids_by_parent_id[None]), True))
|
||||
while _queue:
|
||||
parent_id, parent_is_active = _queue.pop()
|
||||
for instance_id in self._instance_ids_by_parent_id[parent_id]:
|
||||
if not instance_ids:
|
||||
break
|
||||
|
||||
chilren_ids, is_parent_active = _queue.pop()
|
||||
for instance_id in chilren_ids:
|
||||
widget = self._widgets_by_id[instance_id]
|
||||
add_children = False
|
||||
if instance_id in instance_ids:
|
||||
add_children = (
|
||||
is_parent_active is not widget.is_parent_active()
|
||||
)
|
||||
|
||||
if instance_id in available_ids:
|
||||
available_ids.discard(instance_id)
|
||||
widget.update_instance(
|
||||
instance_items_by_id[instance_id],
|
||||
context_info_by_id[instance_id],
|
||||
is_parent_active,
|
||||
)
|
||||
else:
|
||||
# TODO implement 'set_parent_active'
|
||||
widget.set_parent_active(is_parent_active)
|
||||
|
||||
instance_ids.discard(instance_id)
|
||||
discarted_ids.add(instance_id)
|
||||
# TODO there is no way how to get current state
|
||||
parent_is_active_by_id[instance_id] = parent_is_active
|
||||
|
||||
for widget in self._widgets_by_group.values():
|
||||
widget.update_instance_values(
|
||||
context_info_by_id,
|
||||
instance_items_by_id,
|
||||
instance_ids,
|
||||
parent_is_active_by_id,
|
||||
)
|
||||
if not instance_ids:
|
||||
break
|
||||
|
||||
def _on_active_changed(self, group_name, instance_id, value):
|
||||
group_widget = self._widgets_by_group[group_name]
|
||||
instance_widget = group_widget.get_widget_by_item_id(instance_id)
|
||||
if not add_children:
|
||||
continue
|
||||
|
||||
children_ids = self._instance_ids_by_parent_id[instance_id]
|
||||
children = {
|
||||
child_id
|
||||
for child_id in children_ids
|
||||
if child_id not in discarted_ids
|
||||
}
|
||||
|
||||
if children:
|
||||
_queue.append((children, widget.is_active()))
|
||||
|
||||
def _on_active_changed(self, instance_id, value):
|
||||
instance_widget = self._widgets_by_id[instance_id]
|
||||
active_state_by_id = {}
|
||||
if not instance_widget.is_selected:
|
||||
active_state_by_id[instance_id] = value
|
||||
|
|
@ -973,10 +959,9 @@ class InstanceCardView(AbstractInstanceView):
|
|||
|
||||
else:
|
||||
if group_name == CONVERTOR_ITEM_GROUP:
|
||||
group_widget = self._convertor_items_group
|
||||
new_widget = self._convertor_widgets_by_id[instance_id]
|
||||
else:
|
||||
group_widget = self._widgets_by_group[group_name]
|
||||
new_widget = group_widget.get_widget_by_item_id(instance_id)
|
||||
new_widget = self._widgets_by_id[instance_id]
|
||||
|
||||
if selection_type == SelectionTypes.clear:
|
||||
self._select_item_clear(instance_id, group_name, new_widget)
|
||||
|
|
@ -1021,11 +1006,21 @@ class InstanceCardView(AbstractInstanceView):
|
|||
if instance_id == CONTEXT_ID:
|
||||
remove_group = True
|
||||
else:
|
||||
has_selected_items = False
|
||||
if group_name == CONVERTOR_ITEM_GROUP:
|
||||
group_widget = self._convertor_items_group
|
||||
for widget in self._convertor_widgets_by_id.values():
|
||||
if widget.is_selected:
|
||||
has_selected_items = True
|
||||
break
|
||||
else:
|
||||
group_widget = self._widgets_by_group[group_name]
|
||||
if not group_widget.get_selected_widgets():
|
||||
group_ids = self._instance_ids_by_group_name[group_name]
|
||||
for instance_id in group_ids:
|
||||
widget = self._widgets_by_id[instance_id]
|
||||
if widget.is_selected:
|
||||
has_selected_items = True
|
||||
break
|
||||
|
||||
if not has_selected_items:
|
||||
remove_group = True
|
||||
|
||||
if remove_group:
|
||||
|
|
@ -1137,10 +1132,16 @@ class InstanceCardView(AbstractInstanceView):
|
|||
sorted_widgets = [self._context_widget]
|
||||
else:
|
||||
if name == CONVERTOR_ITEM_GROUP:
|
||||
group_widget = self._convertor_items_group
|
||||
sorted_widgets = [
|
||||
self._convertor_widgets_by_id[conv_id]
|
||||
for conv_id in self._convertor_ids
|
||||
]
|
||||
else:
|
||||
group_widget = self._widgets_by_group[name]
|
||||
sorted_widgets = group_widget.get_ordered_widgets()
|
||||
instance_ids = self._instance_ids_by_group_name[name]
|
||||
sorted_widgets = [
|
||||
self._widgets_by_id[instance_id]
|
||||
for instance_id in instance_ids
|
||||
]
|
||||
|
||||
# Change selection based on explicit selection if start group
|
||||
# was not passed yet
|
||||
|
|
@ -1298,12 +1299,19 @@ class InstanceCardView(AbstractInstanceView):
|
|||
|
||||
is_convertor_group = group_name == CONVERTOR_ITEM_GROUP
|
||||
if is_convertor_group:
|
||||
group_widget = self._convertor_items_group
|
||||
sorted_widgets = [
|
||||
self._convertor_widgets_by_id[conv_id]
|
||||
for conv_id in self._convertor_ids
|
||||
]
|
||||
else:
|
||||
group_widget = self._widgets_by_group[group_name]
|
||||
instance_ids = self._instance_ids_by_group_name[group_name]
|
||||
sorted_widgets = [
|
||||
self._widgets_by_id[instance_id]
|
||||
for instance_id in instance_ids
|
||||
]
|
||||
|
||||
group_selected = False
|
||||
for widget in group_widget.get_ordered_widgets():
|
||||
for widget in sorted_widgets:
|
||||
select = False
|
||||
if is_convertor_group:
|
||||
is_in = widget.identifier in s_convertor_identifiers
|
||||
|
|
@ -1325,5 +1333,5 @@ class InstanceCardView(AbstractInstanceView):
|
|||
if self._active_toggle_enabled is enabled:
|
||||
return
|
||||
self._active_toggle_enabled = enabled
|
||||
for group_widget in self._widgets_by_group.values():
|
||||
group_widget.set_active_toggle_enabled(enabled)
|
||||
for widget in self._widgets_by_id.values():
|
||||
widget.set_active_toggle_enabled(enabled)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue