mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-07-20 04:26:19 +02:00
refactor(ui): refactor preview panel into new MVC pattern
This commit is contained in:
@@ -4,16 +4,19 @@
|
||||
|
||||
import typing
|
||||
from pathlib import Path
|
||||
from typing import override
|
||||
from warnings import catch_warnings
|
||||
|
||||
import structlog
|
||||
from PySide6 import QtCore
|
||||
from PySide6.QtGui import QShortcut
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from tagstudio.core.library.alchemy.fields import BaseFieldTemplate
|
||||
from tagstudio.core.library.alchemy.models import Entry
|
||||
from tagstudio.core.utils.ffmpeg_status import FfmpegStatus, FfprobeStatus
|
||||
from tagstudio.qt.mixed.file_attributes import FileAttributeData
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.mixed.field_containers import FieldContainers
|
||||
from tagstudio.qt.mixed.file_attributes import FileAttributeData, FileAttributes
|
||||
from tagstudio.qt.views.preview_panel_view import PreviewPanelView
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
@@ -22,93 +25,189 @@ if typing.TYPE_CHECKING:
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
class PreviewPanel(PreviewPanelView):
|
||||
class PreviewPanel(QWidget):
|
||||
def __init__(self, driver: "QtDriver") -> None:
|
||||
super().__init__(driver)
|
||||
|
||||
self.__current_stats: FileAttributeData | None = None
|
||||
self._thumb.check_ffmpeg.connect(self._toggle_ffmpeg_warning)
|
||||
super().__init__()
|
||||
self._layout = PreviewPanelView(driver=driver, pixel_ratio=self.devicePixelRatio())
|
||||
self._driver = driver
|
||||
self._lib = self._driver.lib
|
||||
self._selected: list[int]
|
||||
self._current_stats: FileAttributeData | None = None
|
||||
|
||||
key = QtCore.QKeyCombination(
|
||||
QtCore.Qt.KeyboardModifier(QtCore.Qt.KeyboardModifier.ControlModifier),
|
||||
QtCore.Qt.Key.Key_T,
|
||||
)
|
||||
self.add_tag_action = QShortcut(key, self)
|
||||
self._add_tag_action = QShortcut(key, self)
|
||||
|
||||
self.__connect_callbacks()
|
||||
self.setLayout(self._layout)
|
||||
self._connect_callbacks()
|
||||
|
||||
def __connect_callbacks(self) -> None:
|
||||
self._add_field_button.clicked.connect(self._add_field_button_callback)
|
||||
self._add_tag_button.clicked.connect(self._add_tag_button_callback)
|
||||
self._thumb.stats_updated.connect(self.__thumb_stats_updated_callback)
|
||||
self.add_tag_action.activated.connect(self._add_tag_button.setFocus)
|
||||
self.add_tag_action.activated.connect(self._add_tag_button.click)
|
||||
|
||||
self.tag_search_box.done.connect(self.tag_added_callback)
|
||||
self.tag_search_box.tags_updated.connect(self.update_added_callback)
|
||||
def _connect_callbacks(self) -> None:
|
||||
self._layout.add_field_button.clicked.connect(self._add_field_button_callback)
|
||||
self._layout.add_tag_button.clicked.connect(self._add_tag_button_callback)
|
||||
self._layout.preview_thumb.stats_updated.connect(self._thumb_stats_updated_callback)
|
||||
self._add_tag_action.activated.connect(self._layout.add_tag_button.setFocus)
|
||||
self._add_tag_action.activated.connect(self._layout.add_tag_button.click)
|
||||
self._layout.tag_search_box.done.connect(self.tag_added_callback)
|
||||
self._layout.tag_search_box.tags_updated.connect(self._update_added_callback)
|
||||
self._layout.preview_thumb.check_ffmpeg.connect(self._toggle_ffmpeg_warning)
|
||||
|
||||
def _add_field_button_callback(self) -> None:
|
||||
# self.__add_field_modal.show()
|
||||
pass
|
||||
|
||||
def _add_tag_button_callback(self) -> None:
|
||||
self.tag_search_box.added = self._containers.tags
|
||||
self.tag_search_box.layout().search_field.setDisabled(False)
|
||||
self.tag_search_box.setHidden(False)
|
||||
self._add_tag_button.setHidden(True)
|
||||
self._add_field_button.setHidden(True)
|
||||
self._layout.tag_search_box.added = self._layout.containers.tags
|
||||
self._layout.tag_search_box.layout().search_field.setDisabled(False)
|
||||
self._layout.tag_search_box.setHidden(False)
|
||||
self._layout.add_tag_button.setHidden(True)
|
||||
self._layout.add_field_button.setHidden(True)
|
||||
|
||||
def tag_added_callback(self):
|
||||
self.tag_search_box.setHidden(True)
|
||||
self._add_tag_button.setHidden(False)
|
||||
self._add_field_button.setHidden(False)
|
||||
self._layout.tag_search_box.setHidden(True)
|
||||
self._layout.add_tag_button.setHidden(False)
|
||||
self._layout.add_field_button.setHidden(False)
|
||||
|
||||
self._add_tag_button.setFocus()
|
||||
self._layout.add_tag_button.setFocus()
|
||||
|
||||
def update_added_callback(self):
|
||||
self.tag_search_box.added = self._containers.tags
|
||||
def _update_added_callback(self):
|
||||
self._layout.tag_search_box.added = self._layout.containers.tags
|
||||
|
||||
def __thumb_stats_updated_callback(self, filepath: Path, stats: FileAttributeData) -> None:
|
||||
def _thumb_stats_updated_callback(self, filepath: Path, stats: FileAttributeData) -> None:
|
||||
if len(self._selected) != 1:
|
||||
return
|
||||
|
||||
if filepath != self._thumb.current_file:
|
||||
if filepath != self._layout.preview_thumb.current_file:
|
||||
return
|
||||
|
||||
if self.__current_stats is None:
|
||||
self.__current_stats = FileAttributeData()
|
||||
if self._current_stats is None:
|
||||
self._current_stats = FileAttributeData()
|
||||
|
||||
if stats.width is not None:
|
||||
self.__current_stats.width = stats.width
|
||||
self._current_stats.width = stats.width
|
||||
if stats.height is not None:
|
||||
self.__current_stats.height = stats.height
|
||||
self._current_stats.height = stats.height
|
||||
if stats.duration is not None:
|
||||
self.__current_stats.duration = stats.duration
|
||||
self._current_stats.duration = stats.duration
|
||||
|
||||
self._file_attrs.update_stats(filepath, self.__current_stats)
|
||||
self._layout.file_attrs.update_stats(filepath, self._current_stats)
|
||||
|
||||
@override
|
||||
def _set_selection_callback(self) -> None:
|
||||
with catch_warnings(record=True):
|
||||
self.field_search_box.field_template_chosen.disconnect()
|
||||
self.tag_search_box.item_chosen.disconnect()
|
||||
self._layout.field_search_box.field_template_chosen.disconnect()
|
||||
self._layout.tag_search_box.item_chosen.disconnect()
|
||||
|
||||
self.field_search_box.field_template_chosen.connect(self._add_field_to_selected)
|
||||
self.tag_search_box.item_chosen.connect(self._add_tag_to_selected)
|
||||
self._layout.field_search_box.field_template_chosen.connect(self._add_field_to_selected)
|
||||
self._layout.tag_search_box.item_chosen.connect(self._add_tag_to_selected)
|
||||
|
||||
def _add_field_to_selected(self, template: BaseFieldTemplate) -> None:
|
||||
self._containers.add_field_to_selected(template)
|
||||
self._layout.containers.add_field_to_selected(template)
|
||||
if len(self._selected) == 1:
|
||||
self._containers.update_from_entry(self._selected[0])
|
||||
self._layout.containers.update_from_entry(self._selected[0])
|
||||
|
||||
def _add_tag_to_selected(self, tag_id: int) -> None:
|
||||
self._containers.add_tags_to_selected(tag_id)
|
||||
self._layout.containers.add_tags_to_selected(tag_id)
|
||||
if len(self._selected) == 1:
|
||||
self._containers.update_from_entry(self._selected[0])
|
||||
self._layout.containers.update_from_entry(self._selected[0])
|
||||
|
||||
def _toggle_ffmpeg_warning(self, enable_warning: bool = True) -> None:
|
||||
if enable_warning and (not FfmpegStatus.which() or not FfprobeStatus.which()):
|
||||
self._ffmpeg_warning_widget.show()
|
||||
self._layout.warning_banner.show()
|
||||
return
|
||||
|
||||
self._ffmpeg_warning_widget.hide()
|
||||
self._layout.warning_banner.hide()
|
||||
|
||||
def set_selection(self, selected: list[int], update_preview: bool = True) -> None:
|
||||
"""Render the panel widgets with the newest data from the Library.
|
||||
|
||||
Args:
|
||||
selected (list[int]): List of the IDs of the selected entries.
|
||||
update_preview (bool): Should the file preview be updated?
|
||||
(Only works with one or more items selected)
|
||||
"""
|
||||
self._selected = selected
|
||||
try:
|
||||
# No Items Selected
|
||||
if len(selected) == 0:
|
||||
self._layout.preview_thumb.hide_preview()
|
||||
self._current_stats = None
|
||||
self._layout.file_attrs.update_stats()
|
||||
self._layout.file_attrs.update_date_label()
|
||||
self._layout.containers.hide_containers()
|
||||
|
||||
self._layout.add_tag_button.setEnabled(False)
|
||||
self._layout.add_field_button.setEnabled(False)
|
||||
self._layout.add_tag_button.setHidden(False)
|
||||
self._layout.add_field_button.setHidden(False)
|
||||
self._layout.tag_search_box.hide_and_reset()
|
||||
|
||||
# One Item Selected
|
||||
elif len(selected) == 1:
|
||||
entry_id = selected[0]
|
||||
entry: Entry = unwrap(self._lib.get_entry(entry_id))
|
||||
|
||||
filepath: Path = unwrap(self._lib.library_dir) / entry.path
|
||||
if filepath != self._layout.preview_thumb.current_file:
|
||||
self._current_stats = None
|
||||
|
||||
if update_preview:
|
||||
stats: FileAttributeData = self._layout.preview_thumb.display_file(filepath)
|
||||
self._current_stats = stats
|
||||
self._layout.file_attrs.update_stats(filepath, stats)
|
||||
self._layout.file_attrs.update_date_label(filepath)
|
||||
self._layout.containers.update_from_entry(entry_id)
|
||||
|
||||
self._set_selection_callback()
|
||||
|
||||
self._layout.add_tag_button.setEnabled(True)
|
||||
self._layout.add_field_button.setEnabled(True)
|
||||
self._layout.add_tag_button.setHidden(False)
|
||||
self._layout.add_field_button.setHidden(False)
|
||||
self._layout.tag_search_box.hide_and_reset()
|
||||
|
||||
# Multiple Selected Items
|
||||
elif len(selected) > 1:
|
||||
# items: list[Entry] = [self.lib.get_entry_full(x) for x in self.driver.selected]
|
||||
self._layout.preview_thumb.hide_preview() # TODO: Render mixed selection
|
||||
self._current_stats = None
|
||||
self._layout.file_attrs.update_multi_selection(len(selected))
|
||||
self._layout.file_attrs.update_date_label()
|
||||
self._layout.containers.hide_containers() # TODO: Allow for mixed editing
|
||||
|
||||
self._set_selection_callback()
|
||||
|
||||
self._layout.add_tag_button.setEnabled(True)
|
||||
self._layout.add_field_button.setEnabled(True)
|
||||
self._layout.add_tag_button.setHidden(False)
|
||||
self._layout.add_field_button.setHidden(False)
|
||||
self._layout.tag_search_box.hide_and_reset()
|
||||
|
||||
except Exception as e:
|
||||
logger.error("[Preview Panel] Error updating selection", error=e)
|
||||
|
||||
def stop_media_playback(self) -> None:
|
||||
"""Stop any media playback in the preview panel."""
|
||||
self._layout.preview_thumb.media_player.stop()
|
||||
|
||||
@property
|
||||
def add_buttons_enabled(self) -> bool: # needed for the tests
|
||||
field = self._layout.add_field_button.isEnabled()
|
||||
tag = self._layout.add_tag_button.isEnabled()
|
||||
assert field == tag
|
||||
return field
|
||||
|
||||
@add_buttons_enabled.setter
|
||||
def add_buttons_enabled(self, enabled: bool) -> None:
|
||||
self._layout.add_field_button.setEnabled(enabled)
|
||||
self._layout.add_tag_button.setEnabled(enabled)
|
||||
|
||||
@property
|
||||
def file_attributes_widget(self) -> FileAttributes: # needed for the tests
|
||||
"""Getter for the file attributes widget."""
|
||||
return self._layout.file_attrs
|
||||
|
||||
@property
|
||||
def field_containers_widget(self) -> FieldContainers: # needed for the tests
|
||||
"""Getter for the field containers widget."""
|
||||
return self._layout.containers
|
||||
|
||||
@@ -963,7 +963,7 @@ class QtDriver(DriverMixin, QObject):
|
||||
for i, tup in enumerate(pending):
|
||||
e_id, f = tup
|
||||
if (origin_path == f) or (not origin_path):
|
||||
self.main_window.preview_panel.preview_thumb.media_player.stop()
|
||||
self.main_window.preview_panel.stop_media_playback()
|
||||
|
||||
msg = Translations.format(
|
||||
"status.deleting_file", i=i, count=len(pending), path=f
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
|
||||
|
||||
import math
|
||||
import traceback
|
||||
import typing
|
||||
from pathlib import Path
|
||||
|
||||
import structlog
|
||||
from PySide6.QtCore import Qt
|
||||
@@ -13,14 +11,12 @@ from PySide6.QtGui import QDesktopServices
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QSplitter, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.constants import FFMPEG_HELP_URL
|
||||
from tagstudio.core.library.alchemy.models import Entry
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
from tagstudio.qt.controllers.field_template_search_panel_controller import FieldTemplateSearchPanel
|
||||
from tagstudio.qt.controllers.preview_thumb_controller import PreviewThumb
|
||||
from tagstudio.qt.controllers.return_button import ReturnButton
|
||||
from tagstudio.qt.controllers.tag_suggest_box import TagSuggestBox
|
||||
from tagstudio.qt.mixed.field_containers import FieldContainers
|
||||
from tagstudio.qt.mixed.file_attributes import FileAttributeData, FileAttributes
|
||||
from tagstudio.qt.mixed.file_attributes import FileAttributes
|
||||
from tagstudio.qt.resource_manager import ResourceManager
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.views.field_template_search_panel_view import FieldTemplateSearchPanelView
|
||||
@@ -33,16 +29,17 @@ if typing.TYPE_CHECKING:
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
class PreviewPanelView(QWidget):
|
||||
_selected: list[int]
|
||||
|
||||
def __init__(self, driver: "QtDriver") -> None:
|
||||
class PreviewPanelView(QVBoxLayout):
|
||||
def __init__(self, driver: "QtDriver", pixel_ratio: float) -> None:
|
||||
super().__init__()
|
||||
self._lib = driver.lib
|
||||
# Init Layout
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setSpacing(6)
|
||||
rm = ResourceManager()
|
||||
|
||||
# Search/Create Boxes
|
||||
self.field_search_box: FieldTemplateSearchPanel = FieldTemplateSearchPanel(
|
||||
self._lib,
|
||||
driver.lib,
|
||||
is_field_template_chooser=True,
|
||||
view=FieldTemplateSearchPanelView(is_field_template_chooser=True),
|
||||
)
|
||||
@@ -55,11 +52,9 @@ class PreviewPanelView(QWidget):
|
||||
)
|
||||
self.tag_search_box.hide()
|
||||
|
||||
self._thumb = PreviewThumb(self._lib, driver)
|
||||
self._file_attrs = FileAttributes(self._lib, driver)
|
||||
self._containers = FieldContainers(
|
||||
self._lib, driver
|
||||
) # TODO: this should be name mangled, but is still needed on the controller side atm
|
||||
self.preview_thumb = PreviewThumb(driver.lib, driver)
|
||||
self.file_attrs = FileAttributes(driver.lib, driver)
|
||||
self.containers = FieldContainers(driver.lib, driver)
|
||||
|
||||
# Visual Preview
|
||||
preview_section = QWidget()
|
||||
@@ -68,11 +63,11 @@ class PreviewPanelView(QWidget):
|
||||
preview_layout.setSpacing(6)
|
||||
|
||||
# Warning Banner (Missing FFmpeg, etc.)
|
||||
self._ffmpeg_warning_widget = QWidget()
|
||||
self._ffmpeg_warning_widget.setObjectName("ffmpeg_widget")
|
||||
ffmpeg_warning_layout = QHBoxLayout(self._ffmpeg_warning_widget)
|
||||
self.warning_banner = QWidget()
|
||||
self.warning_banner.setObjectName("ffmpeg_widget")
|
||||
ffmpeg_warning_layout = QHBoxLayout(self.warning_banner)
|
||||
ffmpeg_warning_layout.setContentsMargins(3, 3, 3, 3)
|
||||
self._ffmpeg_warning_widget.setStyleSheet(preview_warning_style())
|
||||
self.warning_banner.setStyleSheet(preview_warning_style())
|
||||
ffmpeg_warning_label = QLabel(
|
||||
Translations.format(
|
||||
"preview.missing_module.multimedia",
|
||||
@@ -85,14 +80,14 @@ class PreviewPanelView(QWidget):
|
||||
)
|
||||
warning_icon = QLabel()
|
||||
warning_icon_pixmap = rm.alert.scaled(
|
||||
math.floor(20 * self.devicePixelRatio()), math.floor(20 * self.devicePixelRatio())
|
||||
math.floor(20 * pixel_ratio), math.floor(20 * pixel_ratio)
|
||||
)
|
||||
warning_icon_pixmap.setDevicePixelRatio(self.devicePixelRatio())
|
||||
warning_icon_pixmap.setDevicePixelRatio(pixel_ratio)
|
||||
warning_icon.setPixmap(warning_icon_pixmap)
|
||||
ffmpeg_warning_layout.addWidget(warning_icon)
|
||||
ffmpeg_warning_layout.addWidget(ffmpeg_warning_label)
|
||||
ffmpeg_warning_layout.setStretch(1, 1)
|
||||
self._ffmpeg_warning_widget.hide()
|
||||
self.warning_banner.hide()
|
||||
|
||||
# File Information
|
||||
info_section = QWidget()
|
||||
@@ -104,136 +99,38 @@ class PreviewPanelView(QWidget):
|
||||
splitter.setOrientation(Qt.Orientation.Vertical)
|
||||
splitter.setHandleWidth(12)
|
||||
|
||||
# Add Tag/Field Buttons
|
||||
add_buttons_container = QWidget()
|
||||
add_buttons_layout = QHBoxLayout(add_buttons_container)
|
||||
add_buttons_layout.setContentsMargins(0, 0, 0, 0)
|
||||
add_buttons_layout.setSpacing(6)
|
||||
|
||||
self._add_tag_button = ReturnButton(Translations["tag.add"])
|
||||
self._add_tag_button.setEnabled(False)
|
||||
self._add_tag_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self._add_tag_button.setMinimumHeight(30)
|
||||
self._add_tag_button.setStyleSheet(button_style())
|
||||
self.add_tag_button = ReturnButton(Translations["tag.add"])
|
||||
self.add_tag_button.setEnabled(False)
|
||||
self.add_tag_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.add_tag_button.setMinimumHeight(30)
|
||||
self.add_tag_button.setStyleSheet(button_style())
|
||||
|
||||
self._add_field_button = ReturnButton(Translations["field.add"])
|
||||
self._add_field_button.setEnabled(False)
|
||||
self._add_field_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self._add_field_button.setMinimumHeight(30)
|
||||
self._add_field_button.setStyleSheet(button_style())
|
||||
self.add_field_button = ReturnButton(Translations["field.add"])
|
||||
self.add_field_button.setEnabled(False)
|
||||
self.add_field_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.add_field_button.setMinimumHeight(30)
|
||||
self.add_field_button.setStyleSheet(button_style())
|
||||
|
||||
add_buttons_layout.addWidget(self._add_tag_button)
|
||||
add_buttons_layout.addWidget(self._add_field_button)
|
||||
add_buttons_layout.addWidget(self.add_tag_button)
|
||||
add_buttons_layout.addWidget(self.add_field_button)
|
||||
add_buttons_layout.addWidget(self.tag_search_box)
|
||||
# add_buttons_layout.addWidget(self.field_search)
|
||||
|
||||
preview_layout.addWidget(self._thumb)
|
||||
info_layout.addWidget(self._ffmpeg_warning_widget)
|
||||
info_layout.addWidget(self._file_attrs)
|
||||
info_layout.addWidget(self._containers)
|
||||
preview_layout.addWidget(self.preview_thumb)
|
||||
info_layout.addWidget(self.warning_banner)
|
||||
info_layout.addWidget(self.file_attrs)
|
||||
info_layout.addWidget(self.containers)
|
||||
|
||||
splitter.addWidget(preview_section)
|
||||
splitter.addWidget(info_section)
|
||||
splitter.setStretchFactor(1, 2)
|
||||
|
||||
root_layout = QVBoxLayout(self)
|
||||
root_layout.setContentsMargins(0, 0, 0, 0)
|
||||
root_layout.addWidget(splitter)
|
||||
root_layout.addWidget(add_buttons_container)
|
||||
|
||||
def _set_selection_callback(self) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_selection(self, selected: list[int], update_preview: bool = True) -> None:
|
||||
"""Render the panel widgets with the newest data from the Library.
|
||||
|
||||
Args:
|
||||
selected (list[int]): List of the IDs of the selected entries.
|
||||
update_preview (bool): Should the file preview be updated?
|
||||
(Only works with one or more items selected)
|
||||
"""
|
||||
self._selected = selected
|
||||
try:
|
||||
# No Items Selected
|
||||
if len(selected) == 0:
|
||||
self._thumb.hide_preview()
|
||||
self.__current_stats = None
|
||||
self._file_attrs.update_stats()
|
||||
self._file_attrs.update_date_label()
|
||||
self._containers.hide_containers()
|
||||
|
||||
self._add_tag_button.setEnabled(False)
|
||||
self._add_field_button.setEnabled(False)
|
||||
self._add_tag_button.setHidden(False)
|
||||
self._add_field_button.setHidden(False)
|
||||
self.tag_search_box.hide_and_reset()
|
||||
|
||||
# One Item Selected
|
||||
elif len(selected) == 1:
|
||||
entry_id = selected[0]
|
||||
entry: Entry = unwrap(self._lib.get_entry(entry_id))
|
||||
|
||||
filepath: Path = unwrap(self._lib.library_dir) / entry.path
|
||||
if filepath != self._thumb.current_file:
|
||||
self.__current_stats = None
|
||||
|
||||
if update_preview:
|
||||
stats: FileAttributeData = self._thumb.display_file(filepath)
|
||||
self.__current_stats = stats
|
||||
self._file_attrs.update_stats(filepath, stats)
|
||||
self._file_attrs.update_date_label(filepath)
|
||||
self._containers.update_from_entry(entry_id)
|
||||
|
||||
self._set_selection_callback()
|
||||
|
||||
self._add_tag_button.setEnabled(True)
|
||||
self._add_field_button.setEnabled(True)
|
||||
self._add_tag_button.setHidden(False)
|
||||
self._add_field_button.setHidden(False)
|
||||
self.tag_search_box.hide_and_reset()
|
||||
|
||||
# Multiple Selected Items
|
||||
elif len(selected) > 1:
|
||||
# items: list[Entry] = [self.lib.get_entry_full(x) for x in self.driver.selected]
|
||||
self._thumb.hide_preview() # TODO: Render mixed selection
|
||||
self.__current_stats = None
|
||||
self._file_attrs.update_multi_selection(len(selected))
|
||||
self._file_attrs.update_date_label()
|
||||
self._containers.hide_containers() # TODO: Allow for mixed editing
|
||||
|
||||
self._set_selection_callback()
|
||||
|
||||
self._add_tag_button.setEnabled(True)
|
||||
self._add_field_button.setEnabled(True)
|
||||
self._add_tag_button.setHidden(False)
|
||||
self._add_field_button.setHidden(False)
|
||||
self.tag_search_box.hide_and_reset()
|
||||
|
||||
except Exception as e:
|
||||
logger.error("[Preview Panel] Error updating selection", error=e)
|
||||
traceback.print_exc()
|
||||
|
||||
@property
|
||||
def add_buttons_enabled(self) -> bool: # needed for the tests
|
||||
field = self._add_field_button.isEnabled()
|
||||
tag = self._add_tag_button.isEnabled()
|
||||
assert field == tag
|
||||
return field
|
||||
|
||||
@add_buttons_enabled.setter
|
||||
def add_buttons_enabled(self, enabled: bool) -> None:
|
||||
self._add_field_button.setEnabled(enabled)
|
||||
self._add_tag_button.setEnabled(enabled)
|
||||
|
||||
@property
|
||||
def _file_attributes_widget(self) -> FileAttributes: # needed for the tests
|
||||
"""Getter for the file attributes widget."""
|
||||
return self._file_attrs
|
||||
|
||||
@property
|
||||
def field_containers_widget(self) -> FieldContainers: # needed for the tests
|
||||
"""Getter for the field containers widget."""
|
||||
return self._containers
|
||||
|
||||
@property
|
||||
def preview_thumb(self) -> PreviewThumb:
|
||||
return self._thumb
|
||||
# Finalize Layout
|
||||
self.addWidget(splitter)
|
||||
self.addWidget(add_buttons_container)
|
||||
|
||||
@@ -74,9 +74,7 @@ def test_file_path_display(
|
||||
entry = qt_driver.lib.get_entry(2)
|
||||
assert isinstance(entry, Entry)
|
||||
filename = entry.path
|
||||
panel._file_attributes_widget.update_stats(
|
||||
filepath=unwrap(qt_driver.lib.library_dir) / filename
|
||||
)
|
||||
panel.file_attributes_widget.update_stats(filepath=unwrap(qt_driver.lib.library_dir) / filename)
|
||||
|
||||
# Generate the expected file string.
|
||||
# This is copied directly from the file_attributes.py file
|
||||
@@ -94,7 +92,7 @@ def test_file_path_display(
|
||||
file_str += f"<b>{'\u200b'.join(part_)}</b>"
|
||||
|
||||
# Assert the file path is displayed correctly
|
||||
assert panel._file_attributes_widget.file_label.text() == file_str
|
||||
assert panel.file_attributes_widget.file_label.text() == file_str
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
Reference in New Issue
Block a user