Skip to content

Commit

Permalink
fix: correct behavior for tag widget search options (TagStudioDev#398)
Browse files Browse the repository at this point in the history
* fix(tags): include cluster in tag_id search

* fix(ui): remove unused tag context menu item

Remove unused "Add to Search" context menu item for tag widgets.

* fix(ui): add tag search from tag_database

Add missing functionality for the "Search for Tag" context menu option + left click functionality inside `tag_database.py` aka the "Tag Manager" panel.

* fix: verify `tag_id:` input in search

* style: remove commented code

* fix: change `Library` import to type check only
  • Loading branch information
CyanVoxel authored and CarterPillow committed Sep 7, 2024
1 parent eaedc5b commit 6269177
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 54 deletions.
50 changes: 13 additions & 37 deletions tagstudio/src/core/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -1349,10 +1349,18 @@ def search_library(
only_missing: bool = "missing" in query or "no file" in query
allow_adv: bool = "filename:" in query_words
tag_only: bool = "tag_id:" in query_words
tag_only_ids: list[int] = []
if allow_adv:
query_words.remove("filename:")
if tag_only:
query_words.remove("tag_id:")
if query_words and query_words[0].isdigit():
tag_only_ids.append(int(query_words[0]))
tag_only_ids.extend(self.get_tag_cluster(int(query_words[0])))
else:
logging.error(
f"[Library][ERROR] Invalid Tag ID in query: {query_words}"
)
# TODO: Expand this to allow for dynamic fields to work.
only_no_author: bool = "no author" in query or "no artist" in query

Expand All @@ -1379,15 +1387,9 @@ def search_library(
all_tag_terms.remove(all_tag_terms[i])
break

# print(all_tag_terms)

# non_entry_count = 0
# Iterate over all Entries =============================================================
for entry in self.entries:
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}')

if allowed_ext == self.is_exclude_list:
# If the entry has tags of any kind, append them to this main tag list.
Expand Down Expand Up @@ -1429,7 +1431,6 @@ def search_library(
# elif query in entry.path.lower():

# NOTE: This searches path and filenames.

if allow_adv:
if [q for q in query_words if (q in str(entry.path).lower())]:
results.append((ItemType.ENTRY, entry.id))
Expand All @@ -1438,17 +1439,14 @@ def search_library(
]:
results.append((ItemType.ENTRY, entry.id))
elif tag_only:
if entry.has_tag(self, int(query_words[0])):
results.append((ItemType.ENTRY, entry.id))
for id in tag_only_ids:
if entry.has_tag(self, id) and entry.id not in results:
results.append((ItemType.ENTRY, entry.id))
break

# elif query in entry.filename.lower():
# self.filtered_entries.append(index)
elif entry_tags:
# function to add entry to results
def add_entry(entry: Entry):
# self.filter_entries.append()
# self.filtered_file_list.append(file)
# results.append((SearchItemType.ENTRY, entry.id))
added = False
for f in entry.fields:
if self.get_field_attr(f, "type") == "collation":
Expand Down Expand Up @@ -1518,26 +1516,6 @@ def add_entry(entry: Entry):
add_entry(entry)
break

# sys.stdout.write(
# f'\r[INFO][FILTER]: {len(self.filtered_file_list)} matches found')
# sys.stdout.flush()

# except:
# # # Put this here to have new non-registered images show up
# # if query == "untagged" or query == "no author" or query == "no artist":
# # self.filtered_file_list.append(file)
# # non_entry_count = non_entry_count + 1
# pass

# end_time = time.time()
# print(
# f'[INFO][FILTER]: {len(self.filtered_entries)} matches found ({(end_time - start_time):.3f} seconds)')

# if non_entry_count:
# print(
# f'[INFO][FILTER]: There are {non_entry_count} new files in {self.source_dir} that do not have entries. These will not appear in most filtered results.')
# if not self.filtered_entries:
# print("[INFO][FILTER]: Filter returned no results.")
else:
for entry in self.entries:
added = False
Expand All @@ -1562,8 +1540,6 @@ def add_entry(entry: Entry):

if not added:
results.append((ItemType.ENTRY, entry.id))
# for file in self._source_filenames:
# self.filtered_file_list.append(file)
results.reverse()
return results

Expand Down Expand Up @@ -2306,7 +2282,7 @@ def get_tag(self, tag_id: int) -> Tag:
return self.tags[self._tag_id_to_index_map[int(tag_id)]]

def get_tag_cluster(self, tag_id: int) -> list[int]:
"""Returns a list of Tag IDs that reference this Tag."""
"""Returns a list of Tag IDs that reference this Tag as its parent."""
if tag_id in self._tag_id_to_cluster_map:
return self._tag_id_to_cluster_map[int(tag_id)]
return []
Expand Down
37 changes: 23 additions & 14 deletions tagstudio/src/qt/modals/tag_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,37 @@
# Licensed under the GPL-3.0 License.
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio

from PySide6.QtCore import Signal, Qt, QSize
import typing

from PySide6.QtCore import QSize, Qt, Signal
from PySide6.QtWidgets import (
QWidget,
QVBoxLayout,
QFrame,
QHBoxLayout,
QLineEdit,
QScrollArea,
QFrame,
QVBoxLayout,
QWidget,
)

from src.core.constants import TAG_COLORS
from src.core.library import Library
from src.qt.widgets.panel import PanelWidget, PanelModal
from src.qt.widgets.tag import TagWidget
from src.qt.modals.build_tag import BuildTagPanel
from src.qt.widgets.panel import PanelModal, PanelWidget
from src.qt.widgets.tag import TagWidget

# Only import for type checking/autocompletion, will not be imported at runtime.
if typing.TYPE_CHECKING:
from src.core.library import Library, Tag
from src.qt.ts_qt import QtDriver


class TagDatabasePanel(PanelWidget):
tag_chosen = Signal(int)

def __init__(self, library):
def __init__(self, library: "Library", driver: "QtDriver"):
super().__init__()
self.lib: Library = library
# self.callback = callback
self.driver: QtDriver = driver
self.first_tag_id = -1
self.tag_limit = 30
# self.selected_tag: int = 0

self.setMinimumSize(300, 400)
self.root_layout = QVBoxLayout(self)
Expand Down Expand Up @@ -133,9 +137,14 @@ def update_tags(self, query: str):
row = QHBoxLayout(container)
row.setContentsMargins(0, 0, 0, 0)
row.setSpacing(3)
tw = TagWidget(self.lib, self.lib.get_tag(tag_id), True, False)
tw.on_edit.connect(
lambda checked=False, t=self.lib.get_tag(tag_id): (self.edit_tag(t.id))
tag: Tag = self.lib.get_tag(tag_id)
tw = TagWidget(self.lib, tag, True, False)
tw.on_edit.connect(lambda checked=False, t=tag: (self.edit_tag(t.id)))
tw.on_click.connect(
lambda checked=False, q=f"tag_id: {tag_id}": (
self.driver.main_window.searchField.setText(q),
self.driver.filter_items(q),
)
)
row.addWidget(tw)
self.scroll_layout.addWidget(container)
Expand Down
5 changes: 4 additions & 1 deletion tagstudio/src/qt/ts_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,10 @@ def clear_select_action_callback(self):

def show_tag_database(self):
self.modal = PanelModal(
TagDatabasePanel(self.lib), "Library Tags", "Library Tags", has_save=False
TagDatabasePanel(self.lib, self),
"Library Tags",
"Library Tags",
has_save=False,
)
self.modal.show()

Expand Down
2 changes: 0 additions & 2 deletions tagstudio/src/qt/widgets/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ def __init__(
# search_for_tag_action.triggered.connect(on_click_callback)
search_for_tag_action.triggered.connect(self.on_click.emit)
self.bg_button.addAction(search_for_tag_action)
add_to_search_action = QAction("Add to Search", self)
self.bg_button.addAction(add_to_search_action)

self.inner_layout = QHBoxLayout()
self.inner_layout.setObjectName("innerLayout")
Expand Down

0 comments on commit 6269177

Please sign in to comment.