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
93 changes: 93 additions & 0 deletions src/tagstudio/qt/controller/components/tag_box_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio


from typing import TYPE_CHECKING, override

import structlog
from PySide6.QtCore import Signal

from tagstudio.core.enums import TagClickActionOption
from tagstudio.core.library.alchemy.enums import BrowsingState
from tagstudio.core.library.alchemy.models import Tag
from tagstudio.qt.modals.build_tag import BuildTagPanel
from tagstudio.qt.view.components.tag_box_view import TagBoxWidgetView
from tagstudio.qt.widgets.panel import PanelModal

if TYPE_CHECKING:
from tagstudio.qt.ts_qt import QtDriver

logger = structlog.get_logger(__name__)


class TagBoxWidget(TagBoxWidgetView):
on_update = Signal()

__entries: list[int] = []

def __init__(self, title: str, driver: "QtDriver"):
super().__init__(title, driver)
self.__driver = driver

def set_entries(self, entries: list[int]) -> None:
self.__entries = entries

@override
def _on_click(self, tag: Tag) -> None: # type: ignore[misc]
match self.__driver.settings.tag_click_action:
case TagClickActionOption.OPEN_EDIT:
self._on_edit(tag)
case TagClickActionOption.SET_SEARCH:
self.__driver.update_browsing_state(BrowsingState.from_tag_id(tag.id))
case TagClickActionOption.ADD_TO_SEARCH:
# NOTE: modifying the ast and then setting that would be nicer
# than this string manipulation, but also much more complex,
# due to needing to implement a visitor that turns an AST to a string
# So if that exists when you read this, change the following accordingly.
current = self.__driver.browsing_history.current
suffix = BrowsingState.from_tag_id(tag.id).query
assert suffix is not None
self.__driver.update_browsing_state(
current.with_search_query(
f"{current.query} {suffix}" if current.query else suffix
)
)

@override
def _on_remove(self, tag: Tag) -> None: # type: ignore[misc]
logger.info(
"[TagBoxWidget] remove_tag",
selected=self.__entries,
)

for entry_id in self.__entries:
self.__driver.lib.remove_tags_from_entries(entry_id, tag.id)

self.on_update.emit()

@override
def _on_edit(self, tag: Tag) -> None: # type: ignore[misc]
build_tag_panel = BuildTagPanel(self.__driver.lib, tag=tag)

edit_modal = PanelModal(
build_tag_panel,
self.__driver.lib.tag_display_name(tag.id),
"Edit Tag",
done_callback=self.on_update.emit,
has_save=True,
)
# TODO - this was update_tag()
edit_modal.saved.connect(
lambda: self.__driver.lib.update_tag(
build_tag_panel.build_tag(),
parent_ids=set(build_tag_panel.parent_ids),
alias_names=set(build_tag_panel.alias_names),
alias_ids=set(build_tag_panel.alias_ids),
)
)
edit_modal.show()

@override
def _on_search(self, tag: Tag) -> None: # type: ignore[misc]
self.__driver.main_window.search_field.setText(f"tag_id:{tag.id}")
self.__driver.update_browsing_state(BrowsingState.from_tag_id(tag.id))
65 changes: 65 additions & 0 deletions src/tagstudio/qt/view/components/tag_box_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio


from collections.abc import Iterable
from typing import TYPE_CHECKING

import structlog

from tagstudio.core.library.alchemy.library import Library
from tagstudio.core.library.alchemy.models import Tag
from tagstudio.qt.flowlayout import FlowLayout
from tagstudio.qt.widgets.fields import FieldWidget
from tagstudio.qt.widgets.tag import TagWidget

if TYPE_CHECKING:
from tagstudio.qt.ts_qt import QtDriver

logger = structlog.get_logger(__name__)


class TagBoxWidgetView(FieldWidget):
__lib: Library

def __init__(self, title: str, driver: "QtDriver") -> None:
super().__init__(title)
self.__lib = driver.lib

self.__root_layout = FlowLayout()
self.__root_layout.enable_grid_optimizations(value=False)
self.__root_layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(self.__root_layout)

def set_tags(self, tags: Iterable[Tag]) -> None:
tags_ = sorted(list(tags), key=lambda tag: self.__lib.tag_display_name(tag.id))
logger.info("[TagBoxWidget] Tags:", tags=tags)
while self.__root_layout.itemAt(0):
self.__root_layout.takeAt(0).widget().deleteLater() # pyright: ignore[reportOptionalMemberAccess]

for tag in tags_:
tag_widget = TagWidget(tag, library=self.__lib, has_edit=True, has_remove=True)

tag_widget.on_click.connect(lambda t=tag: self._on_click(t))

tag_widget.on_remove.connect(lambda t=tag: self._on_remove(t))

tag_widget.on_edit.connect(lambda t=tag: self._on_edit(t))

tag_widget.search_for_tag_action.triggered.connect(
lambda checked=False, t=tag: self._on_search(t)
)

self.__root_layout.addWidget(tag_widget)

def _on_click(self, tag: Tag) -> None:
raise NotImplementedError

def _on_remove(self, tag: Tag) -> None:
raise NotImplementedError

def _on_edit(self, tag: Tag) -> None:
raise NotImplementedError

def _on_search(self, tag: Tag) -> None:
raise NotImplementedError
10 changes: 5 additions & 5 deletions src/tagstudio/qt/widgets/preview/field_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
)
from tagstudio.core.library.alchemy.library import Library
from tagstudio.core.library.alchemy.models import Entry, Tag
from tagstudio.qt.controller.components.tag_box_controller import TagBoxWidget
from tagstudio.qt.translations import Translations
from tagstudio.qt.widgets.datetime_picker import DatetimePicker
from tagstudio.qt.widgets.fields import FieldContainer
from tagstudio.qt.widgets.panel import PanelModal
from tagstudio.qt.widgets.tag_box import TagBoxWidget
from tagstudio.qt.widgets.text import TextWidget
from tagstudio.qt.widgets.text_box_edit import EditTextBox
from tagstudio.qt.widgets.text_line_edit import EditTextLine
Expand Down Expand Up @@ -478,19 +478,19 @@ def write_tag_container(
inner_widget = container.get_inner_widget()

if isinstance(inner_widget, TagBoxWidget):
inner_widget.set_tags(tags)
with catch_warnings(record=True):
inner_widget.updated.disconnect()
inner_widget.on_update.disconnect()

else:
inner_widget = TagBoxWidget(
tags,
"Tags",
self.driver,
)
container.set_inner_widget(inner_widget)
inner_widget.set_entries([e.id for e in self.cached_entries])
inner_widget.set_tags(tags)

inner_widget.updated.connect(
inner_widget.on_update.connect(
lambda: (self.update_from_entry(self.cached_entries[0].id, update_badges=True))
)
else:
Expand Down
136 changes: 0 additions & 136 deletions src/tagstudio/qt/widgets/tag_box.py

This file was deleted.