mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-01-31 07:10:45 +00:00
feat: add setting to not display full filepath (#841)
* feat: add show file path option to settings menu (#4) * feat: implement file path option for file attributes (#10) * feat: implement file path option for file attributes --------- Co-authored-by: Zarko Sesto <sesto@kth.se> * feat: update ui after changing file path setting (#9) * feat: implement file path options for main window (#11) Co-authored-by: Zarko Sesto <sesto@kth.se> * feat: add realtime feedback for setting changes (#13) Co-authored-by: Zarko Sesto <sesto@kth.se> style: formatted code changes with ruff (#16) * tests: Added tests to test file path display and settings menu enhancement: formated using RUFF test: addeded test to check title bar update * fix: move check for file option to correct spot in open_library (#17) * fix: change translate_with_setter to new method (#18) * fix: update call to translator to be inline with upstream (#19) * refactor: update some imports to reflect refactor on upstream (#20) * refactor: update import paths to reflect recent reformat * format: run ruff format * translation: add translations for filepath setting * refactor: store filepath options in integer enum --------- Co-authored-by: RubenSocha <40490633+RubenSocha@users.noreply.github.com> Co-authored-by: ErzaDuNord <102242407+ErzaDuNord@users.noreply.github.com> Co-authored-by: Zarko Sesto <sesto@kth.se> Co-authored-by: BitGatito <usmanbinmujeeb@gmail.com>
This commit is contained in:
@@ -15,11 +15,21 @@ class SettingItems(str, enum.Enum):
|
||||
LIBS_LIST = "libs_list"
|
||||
WINDOW_SHOW_LIBS = "window_show_libs"
|
||||
SHOW_FILENAMES = "show_filenames"
|
||||
SHOW_FILEPATH = "show_filepath"
|
||||
AUTOPLAY = "autoplay_videos"
|
||||
THUMB_CACHE_SIZE_LIMIT = "thumb_cache_size_limit"
|
||||
LANGUAGE = "language"
|
||||
|
||||
|
||||
class ShowFilepathOption(int, enum.Enum):
|
||||
"""Values representing the options for the "show_filenames" setting."""
|
||||
|
||||
SHOW_FULL_PATHS = 0
|
||||
SHOW_RELATIVE_PATHS = 1
|
||||
SHOW_FILENAMES_ONLY = 2
|
||||
DEFAULT = SHOW_RELATIVE_PATHS
|
||||
|
||||
|
||||
class Theme(str, enum.Enum):
|
||||
COLOR_BG_DARK = "#65000000"
|
||||
COLOR_BG_LIGHT = "#22000000"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QComboBox, QFormLayout, QLabel, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.enums import SettingItems
|
||||
from tagstudio.core.enums import SettingItems, ShowFilepathOption
|
||||
from tagstudio.qt.translations import Translations
|
||||
from tagstudio.qt.widgets.panel import PanelWidget
|
||||
|
||||
@@ -63,6 +63,25 @@ class SettingsPanel(PanelWidget):
|
||||
)
|
||||
self.form_layout.addRow(language_label, self.language_combobox)
|
||||
|
||||
filepath_option_map: dict[int, str] = {
|
||||
ShowFilepathOption.SHOW_FULL_PATHS: Translations["settings.filepath.option.full"],
|
||||
ShowFilepathOption.SHOW_RELATIVE_PATHS: Translations[
|
||||
"settings.filepath.option.relative"
|
||||
],
|
||||
ShowFilepathOption.SHOW_FILENAMES_ONLY: Translations["settings.filepath.option.name"],
|
||||
}
|
||||
self.filepath_combobox = QComboBox()
|
||||
self.filepath_combobox.addItems(list(filepath_option_map.values()))
|
||||
filepath_option: int = int(
|
||||
driver.settings.value(
|
||||
SettingItems.SHOW_FILEPATH, defaultValue=ShowFilepathOption.DEFAULT.value, type=int
|
||||
)
|
||||
)
|
||||
filepath_option = 0 if filepath_option not in filepath_option_map else filepath_option
|
||||
self.filepath_combobox.setCurrentIndex(filepath_option)
|
||||
self.filepath_combobox.currentIndexChanged.connect(self.apply_filepath_setting)
|
||||
self.form_layout.addRow(Translations["settings.filepath.label"], self.filepath_combobox)
|
||||
|
||||
self.root_layout.addWidget(self.form_container)
|
||||
self.root_layout.addStretch(1)
|
||||
self.root_layout.addWidget(self.restart_label)
|
||||
@@ -70,3 +89,19 @@ class SettingsPanel(PanelWidget):
|
||||
def get_language(self) -> str:
|
||||
values: list[str] = list(self.languages.values())
|
||||
return values[self.language_combobox.currentIndex()]
|
||||
|
||||
def apply_filepath_setting(self):
|
||||
selected_value = self.filepath_combobox.currentIndex()
|
||||
self.driver.settings.setValue(SettingItems.SHOW_FILEPATH, selected_value)
|
||||
self.driver.update_recent_lib_menu()
|
||||
self.driver.preview_panel.update_widgets()
|
||||
library_directory = self.driver.lib.library_dir
|
||||
if selected_value == ShowFilepathOption.SHOW_FULL_PATHS:
|
||||
display_path = library_directory
|
||||
else:
|
||||
display_path = library_directory.name
|
||||
self.driver.main_window.setWindowTitle(
|
||||
Translations.format(
|
||||
"app.title", base_title=self.driver.base_title, library_dir=display_path
|
||||
)
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ from PySide6.QtWidgets import (
|
||||
import tagstudio.qt.resources_rc # noqa: F401
|
||||
from tagstudio.core.constants import TAG_ARCHIVED, TAG_FAVORITE, VERSION, VERSION_BRANCH
|
||||
from tagstudio.core.driver import DriverMixin
|
||||
from tagstudio.core.enums import LibraryPrefs, MacroID, SettingItems
|
||||
from tagstudio.core.enums import LibraryPrefs, MacroID, SettingItems, ShowFilepathOption
|
||||
from tagstudio.core.library.alchemy.enums import (
|
||||
FieldTypeEnum,
|
||||
FilterState,
|
||||
@@ -1749,6 +1749,11 @@ class QtDriver(DriverMixin, QObject):
|
||||
"""Updates the recent library menu from the latest values from the settings file."""
|
||||
actions: list[QAction] = []
|
||||
lib_items: dict[str, tuple[str, str]] = {}
|
||||
filepath_option: int = int(
|
||||
self.settings.value(
|
||||
SettingItems.SHOW_FILEPATH, defaultValue=ShowFilepathOption.DEFAULT.value, type=int
|
||||
)
|
||||
)
|
||||
|
||||
settings = self.settings
|
||||
settings.beginGroup(SettingItems.LIBS_LIST)
|
||||
@@ -1767,7 +1772,10 @@ class QtDriver(DriverMixin, QObject):
|
||||
for library_key in libs_sorted:
|
||||
path = Path(library_key[1][0])
|
||||
action = QAction(self.open_recent_library_menu)
|
||||
action.setText(str(path))
|
||||
if filepath_option == ShowFilepathOption.SHOW_FULL_PATHS:
|
||||
action.setText(str(path))
|
||||
else:
|
||||
action.setText(str(Path(path).name))
|
||||
action.triggered.connect(lambda checked=False, p=path: self.open_library(p))
|
||||
actions.append(action)
|
||||
|
||||
@@ -1822,7 +1830,15 @@ class QtDriver(DriverMixin, QObject):
|
||||
|
||||
def open_library(self, path: Path) -> None:
|
||||
"""Open a TagStudio library."""
|
||||
message = Translations.format("splash.opening_library", library_path=str(path))
|
||||
filepath_option: int = int(
|
||||
self.settings.value(
|
||||
SettingItems.SHOW_FILEPATH, defaultValue=ShowFilepathOption.DEFAULT.value, type=int
|
||||
)
|
||||
)
|
||||
library_dir_display = (
|
||||
path if filepath_option == ShowFilepathOption.SHOW_FULL_PATHS else path.name
|
||||
)
|
||||
message = Translations.format("splash.opening_library", library_path=library_dir_display)
|
||||
self.main_window.landing_widget.set_status_label(message)
|
||||
self.main_window.statusbar.showMessage(message, 3)
|
||||
self.main_window.repaint()
|
||||
@@ -1867,12 +1883,23 @@ class QtDriver(DriverMixin, QObject):
|
||||
if self.lib.entries_count < 10000:
|
||||
self.add_new_files_callback()
|
||||
|
||||
library_dir_display = self.lib.library_dir
|
||||
filepath_option: int = int(
|
||||
self.settings.value(
|
||||
SettingItems.SHOW_FILEPATH, defaultValue=ShowFilepathOption.DEFAULT.value, type=int
|
||||
)
|
||||
)
|
||||
if filepath_option == ShowFilepathOption.SHOW_FULL_PATHS:
|
||||
library_dir_display = self.lib.library_dir
|
||||
else:
|
||||
library_dir_display = self.lib.library_dir.name
|
||||
|
||||
self.update_libs_list(path)
|
||||
self.main_window.setWindowTitle(
|
||||
Translations.format(
|
||||
"app.title",
|
||||
base_title=self.base_title,
|
||||
library_dir=self.lib.library_dir,
|
||||
library_dir=library_dir_display,
|
||||
)
|
||||
)
|
||||
self.main_window.setAcceptDrops(True)
|
||||
|
||||
@@ -17,7 +17,7 @@ from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QGuiApplication
|
||||
from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget
|
||||
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.core.enums import SettingItems, ShowFilepathOption, Theme
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.core.media_types import MediaCategories
|
||||
from tagstudio.qt.helpers.file_opener import FileOpenerHelper, FileOpenerLabel
|
||||
@@ -96,6 +96,8 @@ class FileAttributes(QWidget):
|
||||
root_layout.addWidget(self.file_label)
|
||||
root_layout.addWidget(self.date_container)
|
||||
root_layout.addWidget(self.dimensions_label)
|
||||
self.library = library
|
||||
self.driver = driver
|
||||
|
||||
def update_date_label(self, filepath: Path | None = None) -> None:
|
||||
"""Update the "Date Created" and "Date Modified" file property labels."""
|
||||
@@ -142,6 +144,18 @@ class FileAttributes(QWidget):
|
||||
self.dimensions_label.setText("")
|
||||
self.dimensions_label.setHidden(True)
|
||||
else:
|
||||
filepath_option = self.driver.settings.value(
|
||||
SettingItems.SHOW_FILEPATH, defaultValue=ShowFilepathOption.DEFAULT.value, type=int
|
||||
)
|
||||
self.library_path = self.library.library_dir
|
||||
display_path = filepath
|
||||
if filepath_option == ShowFilepathOption.SHOW_FULL_PATHS:
|
||||
display_path = filepath
|
||||
elif filepath_option == ShowFilepathOption.SHOW_RELATIVE_PATHS:
|
||||
display_path = Path(filepath).relative_to(self.library_path)
|
||||
elif filepath_option == ShowFilepathOption.SHOW_FILENAMES_ONLY:
|
||||
display_path = Path(filepath.name)
|
||||
|
||||
self.layout().setSpacing(6)
|
||||
self.file_label.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||
self.file_label.set_file_path(filepath)
|
||||
@@ -149,12 +163,14 @@ class FileAttributes(QWidget):
|
||||
|
||||
file_str: str = ""
|
||||
separator: str = f"<a style='color: #777777'><b>{os.path.sep}</a>" # Gray
|
||||
for i, part in enumerate(filepath.parts):
|
||||
for i, part in enumerate(display_path.parts):
|
||||
part_ = part.strip(os.path.sep)
|
||||
if i != len(filepath.parts) - 1:
|
||||
file_str += f"{'\u200b'.join(part_)}{separator}</b>"
|
||||
if i != len(display_path.parts) - 1:
|
||||
file_str += f"{"\u200b".join(part_)}{separator}</b>"
|
||||
else:
|
||||
file_str += f"<br><b>{'\u200b'.join(part_)}</b>"
|
||||
if file_str != "":
|
||||
file_str += "<br>"
|
||||
file_str += f"<b>{"\u200b".join(part_)}</b>"
|
||||
self.file_label.setText(file_str)
|
||||
self.file_label.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.opener = FileOpenerHelper(filepath)
|
||||
|
||||
@@ -223,6 +223,10 @@
|
||||
"select.all": "Select All",
|
||||
"select.clear": "Clear Selection",
|
||||
"settings.clear_thumb_cache.title": "Clear Thumbnail Cache",
|
||||
"settings.filepath.label": "Filepath Visibility",
|
||||
"settings.filepath.option.full": "Show Full Paths",
|
||||
"settings.filepath.option.name": "Show Filenames Only",
|
||||
"settings.filepath.option.relative": "Show Relative Paths",
|
||||
"settings.language": "Language",
|
||||
"settings.open_library_on_start": "Open Library on Start",
|
||||
"settings.restart_required": "Please restart TagStudio for changes to take effect.",
|
||||
|
||||
130
tests/qt/test_file_path_options.py
Normal file
130
tests/qt/test_file_path_options.py
Normal file
@@ -0,0 +1,130 @@
|
||||
import os
|
||||
import pathlib
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from PySide6.QtGui import (
|
||||
QAction,
|
||||
)
|
||||
from PySide6.QtWidgets import QMenu, QMenuBar
|
||||
|
||||
from tagstudio.core.enums import SettingItems, ShowFilepathOption
|
||||
from tagstudio.core.library.alchemy.library import LibraryStatus
|
||||
from tagstudio.qt.modals.settings_panel import SettingsPanel
|
||||
from tagstudio.qt.widgets.preview_panel import PreviewPanel
|
||||
|
||||
|
||||
# Tests to see if the file path setting is applied correctly
|
||||
@pytest.mark.parametrize(
|
||||
"filepath_option",
|
||||
[
|
||||
ShowFilepathOption.SHOW_FULL_PATHS.value,
|
||||
ShowFilepathOption.SHOW_RELATIVE_PATHS.value,
|
||||
ShowFilepathOption.SHOW_FILENAMES_ONLY.value,
|
||||
],
|
||||
)
|
||||
def test_filepath_setting(qtbot, qt_driver, filepath_option):
|
||||
settings_panel = SettingsPanel(qt_driver)
|
||||
qtbot.addWidget(settings_panel)
|
||||
|
||||
# Mock the update_recent_lib_menu method
|
||||
with patch.object(qt_driver, "update_recent_lib_menu", return_value=None):
|
||||
# Set the file path option
|
||||
settings_panel.filepath_combobox.setCurrentIndex(filepath_option)
|
||||
settings_panel.apply_filepath_setting()
|
||||
|
||||
# Assert the setting is applied
|
||||
assert qt_driver.settings.value(SettingItems.SHOW_FILEPATH) == filepath_option
|
||||
|
||||
|
||||
# Tests to see if the file paths are being displayed correctly
|
||||
@pytest.mark.parametrize(
|
||||
"filepath_option, expected_path",
|
||||
[
|
||||
(
|
||||
ShowFilepathOption.SHOW_FULL_PATHS,
|
||||
lambda library: pathlib.Path(library.library_dir / "one/two/bar.md"),
|
||||
),
|
||||
(ShowFilepathOption.SHOW_RELATIVE_PATHS, lambda library: pathlib.Path("one/two/bar.md")),
|
||||
(ShowFilepathOption.SHOW_FILENAMES_ONLY, lambda library: pathlib.Path("bar.md")),
|
||||
],
|
||||
)
|
||||
def test_file_path_display(qt_driver, library, filepath_option, expected_path):
|
||||
panel = PreviewPanel(library, qt_driver)
|
||||
|
||||
# Select 2
|
||||
qt_driver.toggle_item_selection(2, append=False, bridge=False)
|
||||
panel.update_widgets()
|
||||
|
||||
with patch.object(qt_driver.settings, "value", return_value=filepath_option):
|
||||
# Apply the mock value
|
||||
filename = library.get_entry(2).path
|
||||
panel.file_attrs.update_stats(filepath=pathlib.Path(library.library_dir / filename))
|
||||
|
||||
# Generate the expected file string.
|
||||
# This is copied directly from the file_attributes.py file
|
||||
# can be imported as a function in the future
|
||||
display_path = expected_path(library)
|
||||
file_str: str = ""
|
||||
separator: str = f"<a style='color: #777777'><b>{os.path.sep}</a>" # Gray
|
||||
for i, part in enumerate(display_path.parts):
|
||||
part_ = part.strip(os.path.sep)
|
||||
if i != len(display_path.parts) - 1:
|
||||
file_str += f"{"\u200b".join(part_)}{separator}</b>"
|
||||
else:
|
||||
if file_str != "":
|
||||
file_str += "<br>"
|
||||
file_str += f"<b>{"\u200b".join(part_)}</b>"
|
||||
|
||||
# Assert the file path is displayed correctly
|
||||
assert panel.file_attrs.file_label.text() == file_str
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"filepath_option, expected_title",
|
||||
[
|
||||
(
|
||||
ShowFilepathOption.SHOW_FULL_PATHS.value,
|
||||
lambda path, base_title: f"{base_title} - Library '{path}'",
|
||||
),
|
||||
(
|
||||
ShowFilepathOption.SHOW_RELATIVE_PATHS.value,
|
||||
lambda path, base_title: f"{base_title} - Library '{path.name}'",
|
||||
),
|
||||
(
|
||||
ShowFilepathOption.SHOW_FILENAMES_ONLY.value,
|
||||
lambda path, base_title: f"{base_title} - Library '{path.name}'",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_title_update(qtbot, qt_driver, filepath_option, expected_title):
|
||||
base_title = qt_driver.base_title
|
||||
test_path = pathlib.Path("/dev/null")
|
||||
open_status = LibraryStatus(
|
||||
success=True,
|
||||
library_path=test_path,
|
||||
message="",
|
||||
msg_description="",
|
||||
)
|
||||
# Set the file path option
|
||||
qt_driver.settings.setValue(SettingItems.SHOW_FILEPATH, filepath_option)
|
||||
menu_bar = QMenuBar()
|
||||
|
||||
qt_driver.open_recent_library_menu = QMenu(menu_bar)
|
||||
qt_driver.manage_file_ext_action = QAction(menu_bar)
|
||||
qt_driver.save_library_backup_action = QAction(menu_bar)
|
||||
qt_driver.close_library_action = QAction(menu_bar)
|
||||
qt_driver.refresh_dir_action = QAction(menu_bar)
|
||||
qt_driver.tag_manager_action = QAction(menu_bar)
|
||||
qt_driver.color_manager_action = QAction(menu_bar)
|
||||
qt_driver.new_tag_action = QAction(menu_bar)
|
||||
qt_driver.fix_dupe_files_action = QAction(menu_bar)
|
||||
qt_driver.fix_unlinked_entries_action = QAction(menu_bar)
|
||||
qt_driver.clear_thumb_cache_action = QAction(menu_bar)
|
||||
qt_driver.folders_to_tags_action = QAction(menu_bar)
|
||||
|
||||
# Trigger the update
|
||||
qt_driver.init_library(pathlib.Path(test_path), open_status)
|
||||
|
||||
# Assert the title is updated correctly
|
||||
qt_driver.main_window.setWindowTitle.assert_called_with(expected_title(test_path, base_title))
|
||||
Reference in New Issue
Block a user