Merge branch 'main' into Alpha-v9.4

This commit is contained in:
Travis Abendshien
2024-07-03 16:47:16 -07:00
33 changed files with 336 additions and 143 deletions

View File

@@ -163,3 +163,6 @@ TAG_COLORS = [
"cool gray",
"olive",
]
TAG_FAVORITE = 1
TAG_ARCHIVED = 0

View File

@@ -24,3 +24,16 @@ class SearchMode(int, enum.Enum):
AND = 0
OR = 1
class FieldID(int, enum.Enum):
TITLE = 0
AUTHOR = 1
ARTIST = 2
DESCRIPTION = 4
NOTES = 5
TAGS = 6
CONTENT_TAGS = 7
META_TAGS = 8
DATE_PUBLISHED = 14
SOURCE = 21

View File

@@ -5,7 +5,6 @@
"""The Library object and related methods for TagStudio."""
import datetime
import json
import logging
import os
import time
@@ -18,6 +17,7 @@ from pathlib import Path
from typing import cast, Generator
from typing_extensions import Self
from src.core.enums import FieldID
from src.core.json_typing import JsonCollation, JsonEntry, JsonLibary, JsonTag
from src.core.utils.str import strip_punctuation
from src.core.utils.web import strip_web_protocol
@@ -80,7 +80,7 @@ class Entry:
# self.word_count: int = None
def __str__(self) -> str:
return f"\n{self.compressed_dict()}\n"
return str(self.compressed_dict())
def __repr__(self) -> str:
return self.__str__()
@@ -889,12 +889,12 @@ class Library:
and "tagstudio_thumbs" not in f.parts
and not f.is_dir()
):
if f.suffix not in self.ext_list and self.is_exclude_list:
if f.suffix.lower() not in self.ext_list and self.is_exclude_list:
self.dir_file_count += 1
file = f.relative_to(self.library_dir)
if file not in self.filename_to_entry_id_map:
self.files_not_in_library.append(file)
elif f.suffix in self.ext_list and not self.is_exclude_list:
elif f.suffix.lower() in self.ext_list and not self.is_exclude_list:
self.dir_file_count += 1
file = f.relative_to(self.library_dir)
try:
@@ -1382,7 +1382,7 @@ class Library:
# non_entry_count = 0
# Iterate over all Entries =============================================================
for entry in self.entries:
allowed_ext: bool = entry.filename.suffix not in self.ext_list
allowed_ext: bool = entry.filename.suffix.lower() not in self.ext_list
# try:
# entry: Entry = self.entries[self.file_to_library_index_map[self._source_filenames[i]]]
# print(f'{entry}')
@@ -1539,7 +1539,7 @@ class Library:
else:
for entry in self.entries:
added = False
allowed_ext = entry.filename.suffix not in self.ext_list
allowed_ext = entry.filename.suffix.lower() not in self.ext_list
if allowed_ext == self.is_exclude_list:
for f in entry.fields:
if self.get_field_attr(f, "type") == "collation":
@@ -1948,48 +1948,44 @@ class Library:
if data:
# Add a Title Field if the data doesn't already exist.
if data.get("title"):
field_id = 0 # Title Field ID
if not self.does_field_content_exist(entry_id, field_id, data["title"]):
self.add_field_to_entry(entry_id, field_id)
if not self.does_field_content_exist(
entry_id, FieldID.TITLE, data["title"]
):
self.add_field_to_entry(entry_id, FieldID.TITLE)
self.update_entry_field(entry_id, -1, data["title"], "replace")
# Add an Author Field if the data doesn't already exist.
if data.get("author"):
field_id = 1 # Author Field ID
if not self.does_field_content_exist(
entry_id, field_id, data["author"]
entry_id, FieldID.AUTHOR, data["author"]
):
self.add_field_to_entry(entry_id, field_id)
self.add_field_to_entry(entry_id, FieldID.AUTHOR)
self.update_entry_field(entry_id, -1, data["author"], "replace")
# Add an Artist Field if the data doesn't already exist.
if data.get("artist"):
field_id = 2 # Artist Field ID
if not self.does_field_content_exist(
entry_id, field_id, data["artist"]
entry_id, FieldID.ARTIST, data["artist"]
):
self.add_field_to_entry(entry_id, field_id)
self.add_field_to_entry(entry_id, FieldID.ARTIST)
self.update_entry_field(entry_id, -1, data["artist"], "replace")
# Add a Date Published Field if the data doesn't already exist.
if data.get("date_published"):
field_id = 14 # Date Published Field ID
date = str(
datetime.datetime.strptime(
data["date_published"], "%Y-%m-%d %H:%M:%S"
)
)
if not self.does_field_content_exist(entry_id, field_id, date):
self.add_field_to_entry(entry_id, field_id)
if not self.does_field_content_exist(
entry_id, FieldID.DATE_PUBLISHED, date
):
self.add_field_to_entry(entry_id, FieldID.DATE_PUBLISHED)
# entry = self.entries[entry_id]
self.update_entry_field(entry_id, -1, date, "replace")
# Process String Tags if the data doesn't already exist.
if data.get("tags"):
tags_field_id = 6 # Tags Field ID
content_tags_field_id = 7 # Content Tags Field ID
meta_tags_field_id = 8 # Meta Tags Field ID
notes_field_id = 5 # Notes Field ID
tags: list[str] = data["tags"]
# extra: list[str] = []
# for tag in tags:
@@ -2038,7 +2034,7 @@ class Library:
# tag_field_indices = self.get_field_index_in_entry(
# entry_index, tags_field_id)
content_tags_field_indices = self.get_field_index_in_entry(
self.get_entry(entry_id), content_tags_field_id
self.get_entry(entry_id), FieldID.CONTENT_TAGS
)
# meta_tags_field_indices = self.get_field_index_in_entry(
# entry_index, meta_tags_field_id)
@@ -2055,45 +2051,40 @@ class Library:
entry_id, priority_field_index, [matching[0]], "append"
)
else:
self.add_field_to_entry(entry_id, content_tags_field_id)
self.add_field_to_entry(entry_id, FieldID.CONTENT_TAGS)
self.update_entry_field(
entry_id, -1, [matching[0]], "append"
)
# Add all original string tags as a note.
str_tags = f"Original Tags: {tags}"
if not self.does_field_content_exist(
entry_id, notes_field_id, str_tags
):
self.add_field_to_entry(entry_id, notes_field_id)
if not self.does_field_content_exist(entry_id, FieldID.NOTES, str_tags):
self.add_field_to_entry(entry_id, FieldID.NOTES)
self.update_entry_field(entry_id, -1, str_tags, "replace")
# Add a Description Field if the data doesn't already exist.
if "description" in data.keys() and data["description"]:
field_id = 4 # Description Field ID
if data.get("description"):
if not self.does_field_content_exist(
entry_id, field_id, data["description"]
entry_id, FieldID.DESCRIPTION, data["description"]
):
self.add_field_to_entry(entry_id, field_id)
self.add_field_to_entry(entry_id, FieldID.DESCRIPTION)
self.update_entry_field(
entry_id, -1, data["description"], "replace"
)
if "content" in data.keys() and data["content"]:
field_id = 4 # Description Field ID
if data.get("content"):
if not self.does_field_content_exist(
entry_id, field_id, data["content"]
entry_id, FieldID.DESCRIPTION, data["content"]
):
self.add_field_to_entry(entry_id, field_id)
self.add_field_to_entry(entry_id, FieldID.DESCRIPTION)
self.update_entry_field(entry_id, -1, data["content"], "replace")
if "source" in data.keys() and data["source"]:
field_id = 21 # Source Field ID
if data.get("source"):
for source in data["source"].split(" "):
if source and source != " ":
source = strip_web_protocol(string=source)
if not self.does_field_content_exist(
entry_id, field_id, source
entry_id, FieldID.SOURCE, source
):
self.add_field_to_entry(entry_id, field_id)
self.add_field_to_entry(entry_id, FieldID.SOURCE)
self.update_entry_field(entry_id, -1, source, "replace")
def add_field_to_entry(self, entry_id: int, field_id: int) -> None:

View File

@@ -7,6 +7,7 @@
import json
import os
from pathlib import Path
from enum import Enum
from src.core.library import Entry, Library
from src.core.constants import TS_FOLDER_NAME, TEXT_FIELDS

View File

@@ -0,0 +1,16 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
from PySide6.QtWidgets import QPushButton
class QPushButtonWrapper(QPushButton):
"""
This is a customized implementation of the PySide6 QPushButton that allows to suppress the warning that is triggered
by disconnecting a signal that is not currently connected.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.is_connected = False

View File

@@ -24,6 +24,7 @@ class AddFieldModal(QWidget):
# - OR -
# [Cancel] [Save]
super().__init__()
self.is_connected = False
self.lib = library
self.setWindowTitle(f"Add Field")
self.setWindowModality(Qt.WindowModality.ApplicationModal)

View File

@@ -110,4 +110,4 @@ class FileExtensionModal(PanelWidget):
for i in range(self.table.rowCount()):
ext = self.table.item(i, 0)
if ext and ext.text():
self.lib.ext_list.append(ext.text())
self.lib.ext_list.append(ext.text().lower())

View File

@@ -18,6 +18,7 @@ from PySide6.QtWidgets import (
QFrame,
)
from src.core.enums import FieldID
from src.core.library import Library, Tag
from src.core.palette import ColorType, get_tag_color
from src.qt.flowlayout import FlowLayout
@@ -73,13 +74,13 @@ def folders_to_tags(library: Library):
tag = add_folders_to_tree(folders)
if tag:
if not entry.has_tag(library, tag.id):
entry.add_tag(library, tag.id, 6)
entry.add_tag(library, tag.id, FieldID.TAGS)
logging.info("Done")
def reverse_tag(library: Library, tag: Tag, list: list[Tag]) -> list[Tag]:
if list != None:
if list is not None:
list.append(tag)
else:
list = [tag]
@@ -144,7 +145,7 @@ def generate_preview_data(library: Library):
if cut:
branch["dirs"].pop(folder)
if not "tag" in branch:
if "tag" not in branch:
return
if branch["tag"].id == -1 or len(branch["files"]) > 0: # Needs to be first
return False
@@ -289,7 +290,7 @@ class TreeItem(QWidget):
self.children_layout.addWidget(item)
for file in data["files"]:
label = QLabel()
label.setText(" -> " + file)
label.setText(" -> " + str(file))
self.children_layout.addWidget(label)
if len(data["files"]) == 0 and len(data["dirs"].values()) == 0:
@@ -321,7 +322,7 @@ class ModifiedTagWidget(
self.bg_button = QPushButton(self)
self.bg_button.setFlat(True)
if parentTag != None:
if parentTag is not None:
text = f"{tag.name} ({parentTag.name})".replace("&", "&&")
else:
text = tag.name.replace("&", "&&")

View File

@@ -15,7 +15,7 @@ from PySide6.QtWidgets import (
QLineEdit,
QSizePolicy,
)
from src.qt.helpers.qbutton_wrapper import QPushButtonWrapper
# class NumberEdit(QLineEdit):
# def __init__(self, parent=None) -> None:
@@ -50,13 +50,13 @@ class Pagination(QWidget, QObject):
# self.setMinimumHeight(32)
# [<] ----------------------------------
self.prev_button = QPushButton()
self.prev_button = QPushButtonWrapper()
self.prev_button.setText("<")
self.prev_button.setMinimumSize(self.button_size)
self.prev_button.setMaximumSize(self.button_size)
# --- [1] ------------------------------
self.start_button = QPushButton()
self.start_button = QPushButtonWrapper()
self.start_button.setMinimumSize(self.button_size)
self.start_button.setMaximumSize(self.button_size)
# self.start_button.setStyleSheet('background:cyan;')
@@ -104,14 +104,14 @@ class Pagination(QWidget, QObject):
self.end_ellipses.setText(". . .")
# ----------------------------- [42] ---
self.end_button = QPushButton()
self.end_button = QPushButtonWrapper()
self.end_button.setMinimumSize(self.button_size)
self.end_button.setMaximumSize(self.button_size)
# self.end_button.setMaximumHeight(self.button_size.height())
# self.end_button.setStyleSheet('background:red;')
# ---------------------------------- [>]
self.next_button = QPushButton()
self.next_button = QPushButtonWrapper()
self.next_button.setText(">")
self.next_button.setMinimumSize(self.button_size)
self.next_button.setMaximumSize(self.button_size)
@@ -428,16 +428,15 @@ class Pagination(QWidget, QObject):
# print(f'GOTO PAGE: {index}')
self.update_buttons(self.page_count, index)
def _assign_click(self, button: QPushButton, index):
try:
def _assign_click(self, button: QPushButtonWrapper, index):
if button.is_connected:
button.clicked.disconnect()
except RuntimeError:
pass
button.clicked.connect(lambda checked=False, i=index: self._goto_page(i))
button.is_connected = True
def _populate_buffer_buttons(self):
for i in range(max(self.buffer_page_count * 2, 5)):
button = QPushButton()
button = QPushButtonWrapper()
button.setMinimumSize(self.button_size)
button.setMaximumSize(self.button_size)
button.setHidden(True)
@@ -445,7 +444,7 @@ class Pagination(QWidget, QObject):
self.start_buffer_layout.addWidget(button)
for i in range(max(self.buffer_page_count * 2, 5)):
button = QPushButton()
button = QPushButtonWrapper()
button.setMinimumSize(self.button_size)
button.setMaximumSize(self.button_size)
button.setHidden(True)

View File

@@ -64,6 +64,8 @@ from src.core.constants import (
TS_FOLDER_NAME,
VERSION_BRANCH,
VERSION,
TAG_FAVORITE,
TAG_ARCHIVED,
)
from src.core.utils.web import strip_web_protocol
from src.qt.flowlayout import FlowLayout
@@ -1260,8 +1262,8 @@ class QtDriver(QObject):
filepath = self.lib.library_dir / entry.path / entry.filename
item_thumb.set_item_id(entry.id)
item_thumb.assign_archived(entry.has_tag(self.lib, 0))
item_thumb.assign_favorite(entry.has_tag(self.lib, 1))
item_thumb.assign_archived(entry.has_tag(self.lib, TAG_ARCHIVED))
item_thumb.assign_favorite(entry.has_tag(self.lib, TAG_FAVORITE))
# ctrl_down = True if QGuiApplication.keyboardModifiers() else False
# TODO: Change how this works. The click function
# for collations a few lines down should NOT be allowed during modifier keys.

View File

@@ -13,6 +13,7 @@ from PIL import Image, ImageQt
from PySide6.QtCore import Qt, QEvent
from PySide6.QtGui import QPixmap, QEnterEvent
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton
from src.qt.helpers.qbutton_wrapper import QPushButtonWrapper
class FieldContainer(QWidget):
@@ -81,7 +82,7 @@ class FieldContainer(QWidget):
self.title_layout.addStretch(2)
self.copy_button = QPushButton()
self.copy_button = QPushButtonWrapper()
self.copy_button.setMinimumSize(button_size, button_size)
self.copy_button.setMaximumSize(button_size, button_size)
self.copy_button.setFlat(True)
@@ -92,7 +93,7 @@ class FieldContainer(QWidget):
self.title_layout.addWidget(self.copy_button)
self.copy_button.setHidden(True)
self.edit_button = QPushButton()
self.edit_button = QPushButtonWrapper()
self.edit_button.setMinimumSize(button_size, button_size)
self.edit_button.setMaximumSize(button_size, button_size)
self.edit_button.setFlat(True)
@@ -101,7 +102,7 @@ class FieldContainer(QWidget):
self.title_layout.addWidget(self.edit_button)
self.edit_button.setHidden(True)
self.remove_button = QPushButton()
self.remove_button = QPushButtonWrapper()
self.remove_button.setMinimumSize(button_size, button_size)
self.remove_button.setMaximumSize(button_size, button_size)
self.remove_button.setFlat(True)
@@ -124,31 +125,30 @@ class FieldContainer(QWidget):
# self.set_inner_widget(mode)
def set_copy_callback(self, callback: Optional[MethodType]):
try:
if self.copy_button.is_connected:
self.copy_button.clicked.disconnect()
except RuntimeError:
pass
self.copy_callback = callback
self.copy_button.clicked.connect(callback)
if callback is not None:
self.copy_button.is_connected = True
def set_edit_callback(self, callback: Optional[MethodType]):
try:
if self.edit_button.is_connected:
self.edit_button.clicked.disconnect()
except RuntimeError:
pass
self.edit_callback = callback
self.edit_button.clicked.connect(callback)
if callback is not None:
self.edit_button.is_connected = True
def set_remove_callback(self, callback: Optional[Callable]):
try:
if self.remove_button.is_connected:
self.remove_button.clicked.disconnect()
except RuntimeError:
pass
self.remove_callback = callback
self.remove_button.clicked.connect(callback)
self.remove_button.is_connected = True
def set_inner_widget(self, widget: "FieldWidget"):
# widget.setStyleSheet('background-color:green;')

View File

@@ -1,13 +1,11 @@
# Copyright (C) 2024 Travis Abendshien (CyanVoxel).
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
import contextlib
import logging
import os
import time
import typing
from types import FunctionType
from pathlib import Path
from typing import Optional
@@ -23,9 +21,15 @@ from PySide6.QtWidgets import (
QCheckBox,
)
from src.core.enums import FieldID
from src.core.library import ItemType, Library, Entry
from src.core.constants import AUDIO_TYPES, VIDEO_TYPES, IMAGE_TYPES
from src.core.constants import (
AUDIO_TYPES,
VIDEO_TYPES,
IMAGE_TYPES,
TAG_FAVORITE,
TAG_ARCHIVED,
)
from src.qt.flowlayout import FlowWidget
from src.qt.helpers.file_opener import FileOpenerHelper
from src.qt.widgets.thumb_renderer import ThumbRenderer
@@ -38,9 +42,6 @@ ERROR = f"[ERROR]"
WARNING = f"[WARNING]"
INFO = f"[INFO]"
DEFAULT_META_TAG_FIELD = 8
TAG_FAVORITE = 1
TAG_ARCHIVED = 0
logging.basicConfig(format="%(message)s", level=logging.INFO)
@@ -395,19 +396,22 @@ class ItemThumb(FlowWidget):
def update_clickable(self, clickable: typing.Callable):
"""Updates attributes of a thumbnail element."""
# logging.info(f'[GUI] Updating Click Event for element {id(element)}: {id(clickable) if clickable else None}')
try:
if self.thumb_button.is_connected:
self.thumb_button.clicked.disconnect()
except RuntimeError:
pass
if clickable:
self.thumb_button.clicked.connect(clickable)
self.thumb_button.is_connected = True
def update_badges(self):
if self.mode == ItemType.ENTRY:
# logging.info(f'[UPDATE BADGES] ENTRY: {self.lib.get_entry(self.item_id)}')
# logging.info(f'[UPDATE BADGES] ARCH: {self.lib.get_entry(self.item_id).has_tag(self.lib, 0)}, FAV: {self.lib.get_entry(self.item_id).has_tag(self.lib, 1)}')
self.assign_archived(self.lib.get_entry(self.item_id).has_tag(self.lib, 0))
self.assign_favorite(self.lib.get_entry(self.item_id).has_tag(self.lib, 1))
self.assign_archived(
self.lib.get_entry(self.item_id).has_tag(self.lib, TAG_ARCHIVED)
)
self.assign_favorite(
self.lib.get_entry(self.item_id).has_tag(self.lib, TAG_FAVORITE)
)
def set_item_id(self, id: int):
"""
@@ -476,7 +480,7 @@ class ItemThumb(FlowWidget):
entry.add_tag(
self.panel.driver.lib,
tag_id,
field_id=DEFAULT_META_TAG_FIELD,
field_id=FieldID.META_TAGS,
field_index=-1,
)
else:

View File

@@ -40,6 +40,7 @@ from src.qt.widgets.text import TextWidget
from src.qt.widgets.panel import PanelModal
from src.qt.widgets.text_box_edit import EditTextBox
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
@@ -61,6 +62,7 @@ class PreviewPanel(QWidget):
def __init__(self, library: Library, driver: "QtDriver"):
super().__init__()
self.is_connected = False
self.lib = library
self.driver: QtDriver = driver
self.initialized = False
@@ -83,7 +85,7 @@ class PreviewPanel(QWidget):
self.open_file_action = QAction("Open file", self)
self.open_explorer_action = QAction("Open file in explorer", self)
self.preview_img = QPushButton()
self.preview_img = QPushButtonWrapper()
self.preview_img.setMinimumSize(*self.img_button_size)
self.preview_img.setFlat(True)
self.preview_img.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
@@ -218,7 +220,7 @@ class PreviewPanel(QWidget):
self.afb_layout = QVBoxLayout(self.afb_container)
self.afb_layout.setContentsMargins(0, 12, 0, 0)
self.add_field_button = QPushButton()
self.add_field_button = QPushButtonWrapper()
self.add_field_button.setCursor(Qt.CursorShape.PointingHandCursor)
self.add_field_button.setMinimumSize(96, 28)
self.add_field_button.setMaximumSize(96, 28)
@@ -279,7 +281,9 @@ class PreviewPanel(QWidget):
row_layout.addWidget(label)
layout.addLayout(row_layout)
def set_button_style(btn: QPushButton, extras: list[str] | None = None):
def set_button_style(
btn: QPushButtonWrapper | QPushButton, extras: list[str] | None = None
):
base_style = [
f"background-color:{Theme.COLOR_BG.value};",
"border-radius:6px;",
@@ -317,7 +321,6 @@ class PreviewPanel(QWidget):
button.clicked.connect(open_library_button_clicked(full_val))
set_button_style(button)
button_remove = QPushButton("")
button_remove.setCursor(Qt.CursorShape.PointingHandCursor)
button_remove.setFixedWidth(30)
@@ -411,16 +414,16 @@ class PreviewPanel(QWidget):
self.afb_container, Qt.AlignmentFlag.AlignHCenter
)
try:
if self.afm.is_connected:
self.afm.done.disconnect()
if self.add_field_button.is_connected:
self.add_field_button.clicked.disconnect()
except RuntimeError:
pass
# self.afm.done.connect(lambda f: (self.lib.add_field_to_entry(self.selected[0][1], f), self.update_widgets()))
self.afm.done.connect(
lambda f: (self.add_field_to_selected(f), self.update_widgets())
)
self.afm.is_connected = True
self.add_field_button.clicked.connect(self.afm.show)
def add_field_to_selected(self, field_id: int):
@@ -466,10 +469,8 @@ class PreviewPanel(QWidget):
True,
update_on_ratio_change=True,
)
try:
if self.preview_img.is_connected:
self.preview_img.clicked.disconnect()
except RuntimeError:
pass
for i, c in enumerate(self.containers):
c.setHidden(True)
self.preview_img.show()
@@ -588,14 +589,12 @@ class PreviewPanel(QWidget):
f"[PreviewPanel][ERROR] Couldn't Render thumbnail for {filepath} (because of {e})"
)
try:
if self.preview_img.is_connected:
self.preview_img.clicked.disconnect()
except RuntimeError:
pass
self.preview_img.clicked.connect(
lambda checked=False, filepath=filepath: open_file(filepath)
)
self.preview_img.is_connected = True
self.selected = list(self.driver.selected)
for i, f in enumerate(item.fields):
self.write_container(i, f)
@@ -641,10 +640,8 @@ class PreviewPanel(QWidget):
True,
update_on_ratio_change=True,
)
try:
if self.preview_img.is_connected:
self.preview_img.clicked.disconnect()
except RuntimeError:
pass
self.common_fields = []
self.mixed_fields = []
@@ -773,12 +770,12 @@ class PreviewPanel(QWidget):
"""
Replacement for tag_callback.
"""
try:
if self.is_connected:
self.tags_updated.disconnect()
except RuntimeError:
pass
logging.info("[UPDATE CONTAINER] Setting tags updated slot")
self.tags_updated.connect(slot)
self.is_connected = True
# def write_container(self, item:Union[Entry, Collation, Tag], index, field):
def write_container(self, index, field, mixed=False):
@@ -1067,7 +1064,8 @@ class PreviewPanel(QWidget):
)
# remove_mb.setStandardButtons(QMessageBox.StandardButton.Cancel)
remove_mb.setDefaultButton(cancel_button)
remove_mb.setEscapeButton(cancel_button)
result = remove_mb.exec_()
# logging.info(result)
if result == 1:
if result == 3:
callback()

View File

@@ -10,6 +10,7 @@ import typing
from PySide6.QtCore import Signal, Qt
from PySide6.QtWidgets import QPushButton
from src.core.constants import TAG_FAVORITE, TAG_ARCHIVED
from src.core.library import Library, Tag
from src.qt.flowlayout import FlowLayout
from src.qt.widgets.fields import FieldWidget
@@ -141,7 +142,7 @@ class TagBoxWidget(FieldWidget):
# panel.tag_updated.connect(lambda tag: self.lib.update_tag(tag))
self.edit_modal.show()
def add_tag_callback(self, tag_id):
def add_tag_callback(self, tag_id: int):
# self.base_layout.addWidget(TagWidget(self.lib, self.lib.get_tag(tag), True))
# self.tags.append(tag)
logging.info(
@@ -154,7 +155,7 @@ class TagBoxWidget(FieldWidget):
self.driver.lib, tag_id, field_id=id, field_index=-1
)
self.updated.emit()
if tag_id == 0 or tag_id == 1:
if tag_id in (TAG_FAVORITE, TAG_ARCHIVED):
self.driver.update_badges()
# if type((x[0]) == ThumbButton):
@@ -180,7 +181,7 @@ class TagBoxWidget(FieldWidget):
self.driver.lib, tag_id, field_index=index[0]
)
self.updated.emit()
if tag_id == 0 or tag_id == 1:
if tag_id in (TAG_FAVORITE, TAG_ARCHIVED):
self.driver.update_badges()
# def show_add_button(self, value:bool):

View File

@@ -6,10 +6,11 @@
from PySide6 import QtCore
from PySide6.QtCore import QEvent
from PySide6.QtGui import QEnterEvent, QPainter, QColor, QPen, QPainterPath, QPaintEvent
from PySide6.QtWidgets import QWidget, QPushButton
from PySide6.QtWidgets import QWidget
from src.qt.helpers.qbutton_wrapper import QPushButtonWrapper
class ThumbButton(QPushButton):
class ThumbButton(QPushButtonWrapper):
def __init__(self, parent: QWidget, thumb_size: tuple[int, int]) -> None:
super().__init__(parent)
self.thumb_size: tuple[int, int] = thumb_size

View File

@@ -0,0 +1,42 @@
import sys
import pathlib
import pytest
from syrupy.extensions.json import JSONSnapshotExtension
CWD = pathlib.Path(__file__).parent
sys.path.insert(0, str(CWD.parent))
from src.core.library import Tag, Library
@pytest.fixture
def test_tag():
yield Tag(
id=1,
name="Tag Name",
shorthand="TN",
aliases=["First A", "Second A"],
subtags_ids=[2, 3, 4],
color="",
)
@pytest.fixture
def test_library():
lib_dir = CWD / "fixtures" / "library"
lib = Library()
ret_code = lib.open_library(lib_dir)
assert ret_code == 1
# create files for the entries
for entry in lib.entries:
(lib_dir / entry.filename).touch()
yield lib
@pytest.fixture
def snapshot_json(snapshot):
return snapshot.with_defaults(extension_class=JSONSnapshotExtension)

View File

@@ -0,0 +1,6 @@
[
[
"<ItemType.ENTRY: 0>",
2
]
]

View File

@@ -0,0 +1,6 @@
[
[
"<ItemType.ENTRY: 0>",
1
]
]

View File

@@ -0,0 +1,4 @@
[
"{'id': 1, 'filename': 'foo.txt', 'path': '.', 'fields': [{6: [1001]}]}",
"{'id': 2, 'filename': 'bar.txt', 'path': '.', 'fields': [{6: [1000]}]}"
]

View File

@@ -0,0 +1,18 @@
import pytest
def test_open_library(test_library, snapshot_json):
assert test_library.entries == snapshot_json
@pytest.mark.parametrize(
["query"],
[
("First",),
("Second",),
("--nomatch--",),
],
)
def test_library_search(test_library, query, snapshot_json):
res = test_library.search_library(query)
assert res == snapshot_json

View File

@@ -1,18 +1,8 @@
from src.core.library import Tag
def test_subtag(test_tag):
test_tag.remove_subtag(2)
test_tag.remove_subtag(2)
def test_construction():
tag = Tag(
id=1,
name="Tag Name",
shorthand="TN",
aliases=["First A", "Second A"],
subtags_ids=[2, 3, 4],
color="",
)
assert tag
def test_empty_construction():
tag = Tag(id=1, name="", shorthand="", aliases=[], subtags_ids=[], color="")
assert tag
test_tag.add_subtag(5)
# repeated add should not add the subtag
test_tag.add_subtag(5)
assert test_tag.subtag_ids == [3, 4, 5]

View File

@@ -0,0 +1,69 @@
{
"ts-version": "9.3.1",
"ext_list": [
".json",
".xmp",
".aae"
],
"is_exclude_list": true,
"tags": [
{
"id": 0,
"name": "Archived",
"aliases": [
"Archive"
],
"color": "Red"
},
{
"id": 1,
"name": "Favorite",
"aliases": [
"Favorited",
"Favorites"
],
"color": "Yellow"
},
{
"id": 1000,
"name": "first",
"shorthand": "first",
"color": "magenta"
},
{
"id": 1001,
"name": "second",
"shorthand": "second",
"color": "blue"
}
],
"collations": [],
"fields": [],
"macros": [],
"entries": [
{
"id": 1,
"filename": "foo.txt",
"path": ".",
"fields": [
{
"6": [
1001
]
}
]
},
{
"id": 2,
"filename": "bar.txt",
"path": ".",
"fields": [
{
"6": [
1000
]
}
]
}
]
}