mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-02-01 07:39:10 +00:00
feat: send deleted files to system trash
This refactors the file deletion code to send files to the system trash instead of performing a hard deletion. It also fixes deleting video files and GIFs loaded in the Preview Panel.
This commit is contained in:
@@ -14,3 +14,4 @@ pydub==0.25.1
|
||||
mutagen==1.47.0
|
||||
numpy==1.26.4
|
||||
ffmpeg-python==0.2.0
|
||||
Send2Trash==1.8.3
|
||||
BIN
tagstudio/resources/qt/videos/placeholder.mp4
Normal file
BIN
tagstudio/resources/qt/videos/placeholder.mp4
Normal file
Binary file not shown.
@@ -23,6 +23,7 @@ class MediaType(str, Enum):
|
||||
DISK_IMAGE: str = "disk_image"
|
||||
DOCUMENT: str = "document"
|
||||
FONT: str = "font"
|
||||
IMAGE_ANIMATED: str = "image_animated"
|
||||
IMAGE_RAW: str = "image_raw"
|
||||
IMAGE_VECTOR: str = "image_vector"
|
||||
IMAGE: str = "image"
|
||||
@@ -168,6 +169,12 @@ class MediaCategories:
|
||||
".woff",
|
||||
".woff2",
|
||||
}
|
||||
_IMAGE_ANIMATED_SET: set[str] = {
|
||||
".apng",
|
||||
".gif",
|
||||
".webp",
|
||||
".jxl",
|
||||
}
|
||||
_IMAGE_RAW_SET: set[str] = {
|
||||
".arw",
|
||||
".cr2",
|
||||
@@ -317,6 +324,11 @@ class MediaCategories:
|
||||
extensions=_FONT_SET,
|
||||
is_iana=True,
|
||||
)
|
||||
IMAGE_ANIMATED_TYPES: MediaCategory = MediaCategory(
|
||||
media_type=MediaType.IMAGE_ANIMATED,
|
||||
extensions=_IMAGE_ANIMATED_SET,
|
||||
is_iana=False,
|
||||
)
|
||||
IMAGE_RAW_TYPES: MediaCategory = MediaCategory(
|
||||
media_type=MediaType.IMAGE_RAW,
|
||||
extensions=_IMAGE_RAW_SET,
|
||||
@@ -404,6 +416,7 @@ class MediaCategories:
|
||||
DISK_IMAGE_TYPES,
|
||||
DOCUMENT_TYPES,
|
||||
FONT_TYPES,
|
||||
IMAGE_ANIMATED_TYPES,
|
||||
IMAGE_RAW_TYPES,
|
||||
IMAGE_TYPES,
|
||||
IMAGE_VECTOR_TYPES,
|
||||
|
||||
@@ -1,38 +1,30 @@
|
||||
import logging
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from collections.abc import Callable
|
||||
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
|
||||
# Licensed under the GPL-3.0 License.
|
||||
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
|
||||
|
||||
ERROR = f"[ERROR]"
|
||||
WARNING = f"[WARNING]"
|
||||
INFO = f"[INFO]"
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from send2trash import send2trash
|
||||
|
||||
logging.basicConfig(format="%(message)s", level=logging.INFO)
|
||||
|
||||
|
||||
def delete_file(path: str | Path, callback: Callable):
|
||||
_path = str(path)
|
||||
_file = Path(_path)
|
||||
logging.info(f"Deleting file: {_path}")
|
||||
if not _file.exists():
|
||||
logging.error(f"File not found: {_path}")
|
||||
return
|
||||
def delete_file(path: str | Path) -> bool:
|
||||
"""Sends a file to the system trash.
|
||||
|
||||
Args:
|
||||
path (str | Path): The path of the file to delete.
|
||||
"""
|
||||
_path = Path(path)
|
||||
try:
|
||||
_file.unlink()
|
||||
callback()
|
||||
except Exception as exception:
|
||||
logging.exception(exception)
|
||||
|
||||
|
||||
class FileDeleterHelper:
|
||||
def __init__(self, filepath: str | Path):
|
||||
self.filepath = filepath
|
||||
|
||||
def set_filepath(self, filepath: str | Path):
|
||||
self.filepath = filepath
|
||||
|
||||
def set_delete_callback(self, callback: Callable):
|
||||
self.delete_callback = callback
|
||||
|
||||
def delete_file(self):
|
||||
delete_file(self.filepath, self.delete_callback)
|
||||
logging.info(f"[delete_file] Sending to Trash: {_path}")
|
||||
send2trash(_path)
|
||||
return True
|
||||
except PermissionError as e:
|
||||
logging.error(f"[delete_file][ERROR] PermissionError: {e}")
|
||||
except FileNotFoundError:
|
||||
logging.error(f"[delete_file][ERROR] File Not Found: {_path}")
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
return False
|
||||
|
||||
@@ -31,6 +31,20 @@ class ResourceManager:
|
||||
)
|
||||
ResourceManager._initialized = True
|
||||
|
||||
@staticmethod
|
||||
def get_path(id: str) -> Path | None:
|
||||
"""Get a resource's path from the ResourceManager.
|
||||
Args:
|
||||
id (str): The name of the resource.
|
||||
|
||||
Returns:
|
||||
Path: The resource path if found, else None.
|
||||
"""
|
||||
res: dict = ResourceManager._map.get(id)
|
||||
if res:
|
||||
return Path(__file__).parents[2] / "resources" / res.get("path")
|
||||
return None
|
||||
|
||||
def get(self, id: str) -> Any:
|
||||
"""Get a resource from the ResourceManager.
|
||||
This can include resources inside and outside of QResources, and will return
|
||||
|
||||
@@ -90,5 +90,9 @@
|
||||
"thumb_loading": {
|
||||
"path": "qt/images/thumb_loading.png",
|
||||
"mode": "pil"
|
||||
},
|
||||
"placeholder_mp4": {
|
||||
"path": "qt/videos/placeholder.mp4",
|
||||
"mode": "rb"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,9 +69,11 @@ from src.core.constants import (
|
||||
TAG_FAVORITE,
|
||||
TAG_ARCHIVED,
|
||||
)
|
||||
from src.core.media_types import MediaCategories, MediaType
|
||||
from src.core.utils.web import strip_web_protocol
|
||||
from src.qt.flowlayout import FlowLayout
|
||||
from src.qt.main_window import Ui_MainWindow
|
||||
from src.qt.helpers.file_deleter import delete_file
|
||||
from src.qt.helpers.function_iterator import FunctionIterator
|
||||
from src.qt.helpers.custom_runnable import CustomRunnable
|
||||
from src.qt.resource_manager import ResourceManager
|
||||
@@ -532,7 +534,7 @@ class QtDriver(QObject):
|
||||
folders_to_tags_action.triggered.connect(lambda: ftt_modal.show())
|
||||
macros_menu.addAction(folders_to_tags_action)
|
||||
|
||||
# Help Menu ==========================================================
|
||||
# Help Menu ============================================================
|
||||
self.repo_action = QAction("Visit GitHub Repository", menu_bar)
|
||||
self.repo_action.triggered.connect(
|
||||
lambda: webbrowser.open("https://github.com/TagStudioDev/TagStudio")
|
||||
@@ -549,6 +551,9 @@ class QtDriver(QObject):
|
||||
menu_bar.addMenu(window_menu)
|
||||
menu_bar.addMenu(help_menu)
|
||||
|
||||
# ======================================================================
|
||||
|
||||
# Preview Panel --------------------------------------------------------
|
||||
self.preview_panel = PreviewPanel(self.lib, self)
|
||||
l: QHBoxLayout = self.main_window.splitter
|
||||
l.addWidget(self.preview_panel)
|
||||
@@ -824,6 +829,73 @@ class QtDriver(QObject):
|
||||
self.modal.saved.connect(lambda: (panel.save(), self.filter_items("")))
|
||||
self.modal.show()
|
||||
|
||||
def delete_files_callback(self, origin_path: str | Path):
|
||||
"""Callback to send on or more files to the system trash.
|
||||
|
||||
If 0-1 items are currently selected, the origin_path is used to delete the file
|
||||
from the originating context menu item.
|
||||
If there are currently multiple items selected,
|
||||
then the selection buffer is used to determine the files to be deleted.
|
||||
|
||||
Args:
|
||||
origin_path(str): The file path associated with the widget making the call.
|
||||
May or may not be the file targeted, depending on the selection rules.
|
||||
"""
|
||||
_op: Path = Path(origin_path)
|
||||
item = None
|
||||
deleted_count: int = 0
|
||||
filepath: Path = None # Initialize
|
||||
if len(self.selected) <= 1:
|
||||
if self.selected:
|
||||
item = self.lib.get_entry(self.selected[0][1])
|
||||
filepath = self.lib.library_dir / item.path / item.filename
|
||||
# If the file to be deleted is currently being displayed on the Preview Panel,
|
||||
# tell the panel to stop any use of the file.
|
||||
if origin_path == filepath:
|
||||
self.preview_panel.stop_file_use()
|
||||
self.main_window.statusbar.showMessage(f'Deleting file "{origin_path}"...')
|
||||
self.main_window.statusbar.repaint()
|
||||
if delete_file(_op):
|
||||
op_item = self.lib.get_entry_id_from_filepath(_op)
|
||||
self.lib.remove_entry(op_item)
|
||||
self.purge_item_from_navigation(ItemType.ENTRY, op_item)
|
||||
deleted_count += 1
|
||||
elif len(self.selected) > 1:
|
||||
for i, item_pair in enumerate(self.selected):
|
||||
if item_pair[0] == ItemType.ENTRY:
|
||||
item = self.lib.get_entry(item_pair[1])
|
||||
filepath = self.lib.library_dir / item.path / item.filename
|
||||
self.main_window.statusbar.showMessage(
|
||||
f'Deleting file "{filepath}"...'
|
||||
)
|
||||
self.main_window.statusbar.repaint()
|
||||
if delete_file(filepath):
|
||||
self.purge_item_from_navigation(item.type, item.id)
|
||||
self.lib.remove_entry(item.id)
|
||||
deleted_count += 1
|
||||
self.selected.clear()
|
||||
|
||||
self.filter_items()
|
||||
self.preview_panel.update_widgets()
|
||||
|
||||
if len(self.selected) <= 1 and deleted_count == 0:
|
||||
self.main_window.statusbar.showMessage(
|
||||
"No files deleted. Check if any of the files are currently in use."
|
||||
)
|
||||
elif len(self.selected) <= 1 and deleted_count == 1:
|
||||
self.main_window.statusbar.showMessage(f"Deleted {deleted_count} file!")
|
||||
elif len(self.selected) > 1 and deleted_count == 0:
|
||||
self.main_window.statusbar.showMessage(
|
||||
"No files deleted! Check if any of the files are currently in use."
|
||||
)
|
||||
elif len(self.selected) > 1 and deleted_count < len(self.selected):
|
||||
self.main_window.statusbar.showMessage(
|
||||
f"Only deleted {deleted_count} file{'' if deleted_count == 1 else 's'}! Check if any of the files are currently in use"
|
||||
)
|
||||
elif len(self.selected) > 1 and deleted_count == len(self.selected):
|
||||
self.main_window.statusbar.showMessage(f"Deleted {deleted_count} files!")
|
||||
self.main_window.statusbar.repaint()
|
||||
|
||||
def add_new_files_callback(self):
|
||||
"""Runs when user initiates adding new files to the Library."""
|
||||
# # if self.lib.files_not_in_library:
|
||||
@@ -1449,12 +1521,20 @@ class QtDriver(QObject):
|
||||
|
||||
for i, item_thumb in enumerate(self.item_thumbs, start=0):
|
||||
if i < len(self.nav_frames[self.cur_frame_idx].contents):
|
||||
filepath = ""
|
||||
filepath: Path = None # Initialize
|
||||
if self.nav_frames[self.cur_frame_idx].contents[i][0] == ItemType.ENTRY:
|
||||
entry = self.lib.get_entry(
|
||||
self.nav_frames[self.cur_frame_idx].contents[i][1]
|
||||
)
|
||||
filepath = self.lib.library_dir / entry.path / entry.filename
|
||||
filepath: Path = self.lib.library_dir / entry.path / entry.filename
|
||||
|
||||
try:
|
||||
item_thumb.delete_action.triggered.disconnect()
|
||||
except RuntimeWarning:
|
||||
pass
|
||||
item_thumb.delete_action.triggered.connect(
|
||||
lambda checked=False, f=filepath: self.delete_files_callback(f)
|
||||
)
|
||||
|
||||
item_thumb.set_item_id(entry.id)
|
||||
item_thumb.assign_archived(entry.has_tag(self.lib, TAG_ARCHIVED))
|
||||
@@ -1499,7 +1579,9 @@ class QtDriver(QObject):
|
||||
else collation.e_ids_and_pages[0][0]
|
||||
)
|
||||
cover_e = self.lib.get_entry(cover_id)
|
||||
filepath = self.lib.library_dir / cover_e.path / cover_e.filename
|
||||
filepath: Path = (
|
||||
self.lib.library_dir / cover_e.path / cover_e.filename
|
||||
)
|
||||
item_thumb.set_count(str(len(collation.e_ids_and_pages)))
|
||||
item_thumb.update_clickable(
|
||||
clickable=(
|
||||
|
||||
@@ -132,6 +132,7 @@ class FieldContainer(QWidget):
|
||||
def set_copy_callback(self, callback: Optional[MethodType]):
|
||||
if self.copy_button.is_connected:
|
||||
self.copy_button.clicked.disconnect()
|
||||
self.copy_button.is_connected = False
|
||||
|
||||
self.copy_callback = callback
|
||||
self.copy_button.clicked.connect(callback)
|
||||
@@ -141,6 +142,7 @@ class FieldContainer(QWidget):
|
||||
def set_edit_callback(self, callback: Optional[MethodType]):
|
||||
if self.edit_button.is_connected:
|
||||
self.edit_button.clicked.disconnect()
|
||||
self.edit_button.is_connected = False
|
||||
|
||||
self.edit_callback = callback
|
||||
self.edit_button.clicked.connect(callback)
|
||||
@@ -150,10 +152,12 @@ class FieldContainer(QWidget):
|
||||
def set_remove_callback(self, callback: Optional[Callable]):
|
||||
if self.remove_button.is_connected:
|
||||
self.remove_button.clicked.disconnect()
|
||||
self.remove_button.is_connected = False
|
||||
|
||||
self.remove_callback = callback
|
||||
self.remove_button.clicked.connect(callback)
|
||||
self.remove_button.is_connected = True
|
||||
if callback is not None:
|
||||
self.remove_button.is_connected = True
|
||||
|
||||
def set_inner_widget(self, widget: "FieldWidget"):
|
||||
# widget.setStyleSheet('background-color:green;')
|
||||
|
||||
@@ -8,6 +8,7 @@ import time
|
||||
import typing
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import platform
|
||||
|
||||
from PIL import Image, ImageQt
|
||||
from PySide6.QtCore import Qt, QSize, QEvent, QMimeData, QUrl
|
||||
@@ -30,7 +31,6 @@ from src.core.constants import (
|
||||
from src.core.media_types import MediaCategories, MediaType
|
||||
from src.qt.flowlayout import FlowWidget
|
||||
from src.qt.helpers.file_opener import FileOpenerHelper
|
||||
from src.qt.helpers.file_deleter import FileDeleterHelper
|
||||
from src.qt.widgets.thumb_renderer import ThumbRenderer
|
||||
from src.qt.widgets.thumb_button import ThumbButton
|
||||
|
||||
@@ -194,16 +194,19 @@ class ItemThumb(FlowWidget):
|
||||
|
||||
self.thumb_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
|
||||
self.opener = FileOpenerHelper("")
|
||||
self.deleter = FileDeleterHelper("")
|
||||
open_file_action = QAction("Open file", self)
|
||||
open_file_action.triggered.connect(self.opener.open_file)
|
||||
open_explorer_action = QAction("Open file in explorer", self)
|
||||
open_explorer_action.triggered.connect(self.opener.open_explorer)
|
||||
delete_action = QAction("Delete", self)
|
||||
delete_action.triggered.connect(self.deleter.delete_file)
|
||||
|
||||
trash_term: str = "Trash"
|
||||
if platform.system() == "Windows":
|
||||
trash_term = "Recycle Bin"
|
||||
self.delete_action = QAction(f"Send file to {trash_term}", self)
|
||||
|
||||
self.thumb_button.addAction(open_file_action)
|
||||
self.thumb_button.addAction(open_explorer_action)
|
||||
self.thumb_button.addAction(delete_action)
|
||||
self.thumb_button.addAction(self.delete_action)
|
||||
|
||||
# Static Badges ========================================================
|
||||
|
||||
@@ -445,8 +448,6 @@ class ItemThumb(FlowWidget):
|
||||
entry = self.lib.get_entry(self.item_id)
|
||||
filepath = self.lib.library_dir / entry.path / entry.filename
|
||||
self.opener.set_filepath(filepath)
|
||||
self.deleter.set_filepath(filepath)
|
||||
self.deleter.set_delete_callback(self._on_delete)
|
||||
|
||||
def assign_favorite(self, value: bool):
|
||||
# Switching mode to None to bypass mode-specific operations when the
|
||||
@@ -547,9 +548,3 @@ class ItemThumb(FlowWidget):
|
||||
mimedata.setUrls(paths)
|
||||
drag.setMimeData(mimedata)
|
||||
drag.exec(Qt.DropAction.CopyAction)
|
||||
|
||||
def _on_delete(self):
|
||||
entry = self.lib.get_entry(self.item_id)
|
||||
self.lib.remove_entry(self.item_id)
|
||||
self.panel.driver.purge_item_from_navigation(entry.type, self.item_id)
|
||||
self.panel.driver.filter_items()
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import platform
|
||||
import time
|
||||
import typing
|
||||
from datetime import datetime as dt
|
||||
@@ -11,7 +12,7 @@ import cv2
|
||||
import rawpy
|
||||
from PIL import Image, UnidentifiedImageError, ImageFont
|
||||
from PIL.Image import DecompressionBombError
|
||||
from PySide6.QtCore import QModelIndex, Signal, Qt, QSize
|
||||
from PySide6.QtCore import QModelIndex, Signal, Qt, QSize, QByteArray, QBuffer
|
||||
from PySide6.QtGui import QGuiApplication, QResizeEvent, QAction, QMovie
|
||||
from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
@@ -45,6 +46,7 @@ from src.qt.widgets.text_line_edit import EditTextLine
|
||||
from src.qt.helpers.qbutton_wrapper import QPushButtonWrapper
|
||||
from src.qt.widgets.video_player import VideoPlayer
|
||||
from src.qt.helpers.file_tester import is_readable_video
|
||||
from src.qt.resource_manager import ResourceManager
|
||||
|
||||
|
||||
# Only import for type checking/autocompletion, will not be imported at runtime.
|
||||
@@ -98,6 +100,10 @@ class PreviewPanel(QWidget):
|
||||
|
||||
self.open_file_action = QAction("Open file", self)
|
||||
self.open_explorer_action = QAction("Open file in explorer", self)
|
||||
self.trash_term: str = "Trash"
|
||||
if platform.system() == "Windows":
|
||||
self.trash_term = "Recycle Bin"
|
||||
self.delete_action = QAction(f"Send file to {self.trash_term}", self)
|
||||
|
||||
self.preview_img = QPushButtonWrapper()
|
||||
self.preview_img.setMinimumSize(*self.img_button_size)
|
||||
@@ -105,6 +111,7 @@ class PreviewPanel(QWidget):
|
||||
self.preview_img.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
|
||||
self.preview_img.addAction(self.open_file_action)
|
||||
self.preview_img.addAction(self.open_explorer_action)
|
||||
self.preview_img.addAction(self.delete_action)
|
||||
|
||||
self.preview_gif = QLabel()
|
||||
self.preview_gif.setMinimumSize(*self.img_button_size)
|
||||
@@ -112,10 +119,13 @@ class PreviewPanel(QWidget):
|
||||
self.preview_gif.setCursor(Qt.CursorShape.ArrowCursor)
|
||||
self.preview_gif.addAction(self.open_file_action)
|
||||
self.preview_gif.addAction(self.open_explorer_action)
|
||||
self.preview_gif.addAction(self.delete_action)
|
||||
self.preview_gif.hide()
|
||||
self.gif_buffer: QBuffer = QBuffer()
|
||||
|
||||
self.preview_vid = VideoPlayer(driver)
|
||||
self.preview_vid.hide()
|
||||
self.preview_vid.addAction(self.delete_action)
|
||||
self.thumb_renderer = ThumbRenderer()
|
||||
self.thumb_renderer.updated.connect(
|
||||
lambda ts, i, s: (self.preview_img.setIcon(i))
|
||||
@@ -490,6 +500,14 @@ class PreviewPanel(QWidget):
|
||||
)
|
||||
if self.preview_img.is_connected:
|
||||
self.preview_img.clicked.disconnect()
|
||||
self.preview_img.is_connected = False
|
||||
|
||||
try:
|
||||
self.delete_action.triggered.disconnect()
|
||||
except RuntimeWarning:
|
||||
pass
|
||||
self.delete_action.setEnabled(False)
|
||||
|
||||
for i, c in enumerate(self.containers):
|
||||
c.setHidden(True)
|
||||
self.preview_img.show()
|
||||
@@ -529,6 +547,17 @@ class PreviewPanel(QWidget):
|
||||
)
|
||||
self.preview_img.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
|
||||
try:
|
||||
self.delete_action.triggered.disconnect()
|
||||
except RuntimeError:
|
||||
pass
|
||||
self.delete_action.setText(f"Send file to {self.trash_term}")
|
||||
self.delete_action.triggered.connect(
|
||||
lambda checked=False,
|
||||
f=filepath: self.driver.delete_files_callback(f)
|
||||
)
|
||||
self.delete_action.setEnabled(True)
|
||||
|
||||
self.opener = FileOpenerHelper(filepath)
|
||||
self.open_file_action.triggered.connect(self.opener.open_file)
|
||||
self.open_explorer_action.triggered.connect(
|
||||
@@ -539,16 +568,24 @@ class PreviewPanel(QWidget):
|
||||
ext: str = filepath.suffix.lower()
|
||||
try:
|
||||
if filepath.suffix.lower() in [".gif"]:
|
||||
movie = QMovie(str(filepath))
|
||||
with open(filepath, mode="rb") as f:
|
||||
if self.preview_gif.movie():
|
||||
self.preview_gif.movie().stop()
|
||||
self.gif_buffer.close()
|
||||
|
||||
ba = f.read()
|
||||
self.gif_buffer.setData(ba)
|
||||
movie = QMovie(self.gif_buffer, QByteArray())
|
||||
self.preview_gif.setMovie(movie)
|
||||
movie.start()
|
||||
|
||||
image = Image.open(str(filepath))
|
||||
self.preview_gif.setMovie(movie)
|
||||
self.resizeEvent(
|
||||
QResizeEvent(
|
||||
QSize(image.width, image.height),
|
||||
QSize(image.width, image.height),
|
||||
)
|
||||
)
|
||||
movie.start()
|
||||
self.preview_img.hide()
|
||||
self.preview_vid.hide()
|
||||
self.preview_gif.show()
|
||||
@@ -660,6 +697,7 @@ class PreviewPanel(QWidget):
|
||||
# TODO: Implement a clickable label to use for the GIF preview.
|
||||
if self.preview_img.is_connected:
|
||||
self.preview_img.clicked.disconnect()
|
||||
self.preview_img.is_connected = False
|
||||
self.preview_img.clicked.connect(
|
||||
lambda checked=False, filepath=filepath: open_file(filepath)
|
||||
)
|
||||
@@ -701,6 +739,16 @@ class PreviewPanel(QWidget):
|
||||
)
|
||||
self.preview_img.setCursor(Qt.CursorShape.ArrowCursor)
|
||||
|
||||
try:
|
||||
self.delete_action.triggered.disconnect()
|
||||
except RuntimeError:
|
||||
pass
|
||||
self.delete_action.setText(f"Send files to {self.trash_term}")
|
||||
self.delete_action.triggered.connect(
|
||||
lambda checked=False, f=None: self.driver.delete_files_callback(f)
|
||||
)
|
||||
self.delete_action.setEnabled(True)
|
||||
|
||||
ratio: float = self.devicePixelRatio()
|
||||
self.thumb_renderer.render(
|
||||
time.time(),
|
||||
@@ -1140,3 +1188,26 @@ class PreviewPanel(QWidget):
|
||||
# logging.info(result)
|
||||
if result == 3:
|
||||
callback()
|
||||
|
||||
def stop_file_use(self):
|
||||
"""Stops the use of the currently previewed file. Used to release file permissions."""
|
||||
logging.info("[PreviewPanel] Stopping file use in video playback...")
|
||||
# This swaps the video out for a placeholder so the previous video's file
|
||||
# is no longer in use by this object.
|
||||
self.preview_vid.play(ResourceManager.get_path("placeholder_mp4"), QSize(8, 8))
|
||||
self.preview_vid.hide()
|
||||
|
||||
# NOTE: I'm keeping this here until #357 is merged in the case it still needs to be used.
|
||||
# logging.info("[PreviewPanel] Stopping file use for animated image playback...")
|
||||
# logging.info(self.preview_gif.movie())
|
||||
# if self.preview_gif.movie():
|
||||
# self.preview_gif.movie().stop()
|
||||
# with open(ResourceManager.get_path("placeholder_gif"), mode="rb") as f:
|
||||
# ba = f.read()
|
||||
# self.gif_buffer.setData(ba)
|
||||
# movie = QMovie(self.gif_buffer, QByteArray())
|
||||
# self.preview_gif.setMovie(movie)
|
||||
# movie.start()
|
||||
|
||||
# self.preview_gif.hide()
|
||||
# logging.info(self.preview_gif.movie())
|
||||
|
||||
Reference in New Issue
Block a user