Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions src/view/dialogs/asset_mgmt_dialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Contains the asset management dialog."""

from __future__ import annotations

import os

from PySide6.QtGui import QAction, QIcon
from PySide6.QtWidgets import QDialog, QDialogButtonBox, QFileDialog, QMessageBox, QToolBar, QVBoxLayout, QWidget

from controller.utils.process_notifications import ProcessNotifier, get_process_notifier
from model.media_assets.image import LocalImage
from model.media_assets.media_type import MediaType
from view.utility_widgets.asset_selection_widget import AssetSelectionWidget

_SUPPORTED_FILE_ENDINGS: dict[MediaType, list[str]] = {
MediaType.TEXT: [".txt"],
MediaType.IMAGE: [".jpg", ".jpeg", ".png", ".bmp", ".gif", ".pbm", ".pgm", ".ppm", ".xbm", ".xpm"],
MediaType.VIDEO: [".mp4"],
MediaType.AUDIO: [".wav", ".mp3", ".flac"],
MediaType.MODEL_3D: [".stl", ".obj"]
}


class AssetManagementDialog(QDialog):
"""Provide a GUI method to manage assets."""

def __init__(self, parent: QWidget | None = None, show_file_path: str | None = None) -> None:
"""Initialize the asset management dialog."""
super().__init__(parent)
layout = QVBoxLayout()

self._action_button_group = QToolBar()

self._load_asset_file = QAction()
self._load_asset_file.setIcon(QIcon.fromTheme("document-open"))
self._load_asset_file.setText("Load asset from file")
self._load_asset_file.triggered.connect(self._open_file)
self._action_button_group.addAction(self._load_asset_file)

layout.addWidget(self._action_button_group)

self._asset_display = AssetSelectionWidget(self)
layout.addWidget(self._asset_display)

self._close_button_group = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
self._close_button_group.button(QDialogButtonBox.StandardButton.Close).clicked.connect(self.close)
layout.addWidget(self._close_button_group)

self.setLayout(layout)
self.setModal(True)
self._dialog: QFileDialog | None = None
self._show_file_path = show_file_path if show_file_path is not None else ""
self.setMinimumWidth(800)

def _open_file(self) -> None:
self._dialog = QFileDialog(self, "Open file")
self._dialog.setModal(True)
self._dialog.setNameFilters(
[f"{k.get_long_description()} ({" ".join(f"*{va}" for va in v)})"
for k, v in _SUPPORTED_FILE_ENDINGS.items()]
)
self._dialog.setDefaultSuffix(".jpg")
self._dialog.setFileMode(QFileDialog.FileMode.ExistingFiles)
self._dialog.setDirectory(os.path.expanduser("~") if self._show_file_path is None else self._show_file_path)
self._dialog.filesSelected.connect(self._process_loading_files)
self._dialog.open()

def _process_loading_files(self, list_of_files: list[str]) -> None:
self._dialog.close()
if len(list_of_files) == 0:
return
accumulated_errors = ""
pn = get_process_notifier("Asset Loading", len(list_of_files))
for file_path in list_of_files:
pn.current_step_description = f"Loading Asset from {file_path}"
extension = os.path.splitext(file_path)[1]
try:
if extension in _SUPPORTED_FILE_ENDINGS[MediaType.IMAGE]:
LocalImage(file_path, show_file_path=self._show_file_path)
else:
accumulated_errors += f"Unable to load asset from {file_path}: extension {extension} unknown.\n"
except Exception as e:
accumulated_errors += f"Unable to load asset from {file_path}: {e}\n"
pn.current_step_number += 1
self._asset_display.reload_model()
pn.close()
if len(accumulated_errors) > 0:
msg_box = QMessageBox(QMessageBox.Icon.Critical, "Loading Assets Failed",
"Errors occurred during asset loading:", parent=self,
detailedText=accumulated_errors)
msg_box.show()
self._dialog = msg_box
7 changes: 7 additions & 0 deletions src/view/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from utility import resource_path
from view.action_setup_view.combined_action_setup_widget import CombinedActionSetupWidget
from view.console_mode.console_universe_selector import UniverseSelector
from view.dialogs.asset_mgmt_dialog import AssetManagementDialog
from view.dialogs.colum_dialog import ColumnDialog
from view.logging_view.logging_widget import LoggingWidget
from view.main_widget import MainWidget
Expand Down Expand Up @@ -199,6 +200,8 @@ def _setup_menubar(self) -> None:
"Tools": [
# ("Scene Wizard", self._open_scene_setup_wizard, None),
("Patch Plan Export", self._open_patch_plan_export_dialog, None),
("Asset Management", self._open_asset_mgmt_dialog, None),
("---", None, None),
("&Toggle Terminal", self._toggle_terminal, "T"),
],
"Help": [
Expand Down Expand Up @@ -395,3 +398,7 @@ def _toggle_terminal(self) -> None:
else:
self._terminal_widget.show()
self._terminal_widget.focusWidget()

def _open_asset_mgmt_dialog(self) -> None:
self._settings_dialog = AssetManagementDialog(self, self._board_configuration.file_path)
self._settings_dialog.show()
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ def __init__(self, ui_widget: MacroButtonUIWidget, button_list: QListWidget, upd
self._text_tb = QLineEdit(self)
layout.addRow("Display Text: ", self._text_tb)

# TODO add Icon selection from show media storage
self._icon_selection = AssetSelectionWidget(self, allowed_types=[MediaType.IMAGE], multiselection_allowed=False)
layout.addRow("Select Icon", self._icon_selection)
# TODO add clear icon button
Expand Down
15 changes: 10 additions & 5 deletions src/view/utility_widgets/asset_selection_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self) -> None:
self._name_filter: str = ""
self._filtered_asset_list: list[MediaAsset] = []

def apply_filter(self, name: str, types: set[MediaType]) -> None:
def apply_filter(self, name: str, types: set[MediaType], force_update: bool = False) -> None:
"""Apply the filter parameters to the asset selection.

Warning: this operation may be quite expensive. It is therefore better to wait for a filter to be entered
Expand All @@ -39,11 +39,12 @@ def apply_filter(self, name: str, types: set[MediaType]) -> None:
Args:
name: If set to anything than an empty string, all assets needs to contain this in their name.
types: The types of assets to show.
force_update: If set to true, updating the model is forced.

"""
if types == self._selected_media_types and name == self._name_filter:
if (types == self._selected_media_types and name == self._name_filter) and not force_update:
return
if len(name) < len(self._name_filter):
if len(name) < len(self._name_filter) or force_update:
self._filtered_asset_list.clear()
self._selected_media_types.clear()
types_to_add = types - self._selected_media_types
Expand Down Expand Up @@ -199,16 +200,20 @@ def __init__(self, parent: QWidget | None = None, allowed_types: list[MediaType]
self.setLayout(layout)
self._update_filter()

def _update_filter(self) -> None:
def _update_filter(self, force: bool = False) -> None:
selected_types: set[MediaType] = set()
for asset_type, action in self._type_checkboxes:
if action.isChecked():
selected_types.add(asset_type)
self._asset_view.setEnabled(False)
self._model.apply_filter(self._search_bar.text(), selected_types)
self._model.apply_filter(self._search_bar.text(), selected_types, force_update=force)
self._asset_view.setEnabled(True)
self.update()

def reload_model(self) -> None:
"""Forcefully update the model."""
self._update_filter(force=True)

@property
def selected_asset(self) -> list[MediaAsset]:
"""Get or set the selected assets."""
Expand Down