Skip to content

Commit 82edbee

Browse files
authored
ui: shortcut to add tags to selected entries; change click behavior of tags to edit (#749)
* ui: change on_click behavior of tags to edit * fix: pass library to tag_widget * feat: add `add_tag_to_selected` shortcut * fix: only enable `add_tag_to_selected` shortcut when usable
1 parent d1b006a commit 82edbee

3 files changed

Lines changed: 60 additions & 8 deletions

File tree

tagstudio/resources/translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@
183183
"menu.view": "&View",
184184
"menu.window": "Window",
185185
"preview.no_selection": "No Items Selected",
186+
"select.add_tag_to_selected": "Add Tag to Selected",
186187
"select.all": "Select All",
187188
"select.clear": "Clear Selection",
188189
"settings.clear_thumb_cache.title": "Clear Thumbnail Cache",

tagstudio/src/qt/ts_qt.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
from src.qt.modals.fix_unlinked import FixUnlinkedEntriesModal
8282
from src.qt.modals.folders_to_tags import FoldersToTagsModal
8383
from src.qt.modals.tag_database import TagDatabasePanel
84+
from src.qt.modals.tag_search import TagSearchPanel
8485
from src.qt.resource_manager import ResourceManager
8586
from src.qt.splash import Splash
8687
from src.qt.translations import Translations
@@ -132,6 +133,9 @@ class QtDriver(DriverMixin, QObject):
132133
SIGTERM = Signal()
133134

134135
preview_panel: PreviewPanel
136+
tag_search_panel: TagSearchPanel
137+
add_tag_modal: PanelModal
138+
135139
lib: Library
136140

137141
def __init__(self, backend, args):
@@ -199,6 +203,8 @@ def __init__(self, backend, args):
199203
f"[Config] Thumbnail cache size limit: {format_size(CacheManager.size_limit)}",
200204
)
201205

206+
self.add_tag_to_selected_action: QAction | None = None
207+
202208
def init_workers(self):
203209
"""Init workers for rendering thumbnails."""
204210
if not self.thumb_threads:
@@ -270,6 +276,18 @@ def start(self) -> None:
270276
icon.addFile(str(icon_path))
271277
app.setWindowIcon(icon)
272278

279+
# Initialize the main window's tag search panel
280+
self.tag_search_panel = TagSearchPanel(self.lib, is_tag_chooser=True)
281+
self.add_tag_modal = PanelModal(
282+
self.tag_search_panel, Translations.translate_formatted("tag.add.plural")
283+
)
284+
self.tag_search_panel.tag_chosen.connect(
285+
lambda t: (
286+
self.add_tags_to_selected_callback(t),
287+
self.preview_panel.update_widgets(),
288+
)
289+
)
290+
273291
menu_bar = QMenuBar(self.main_window)
274292
self.main_window.setMenuBar(menu_bar)
275293
menu_bar.setNativeMenuBar(True)
@@ -394,6 +412,24 @@ def start(self) -> None:
394412
clear_select_action.setToolTip("Esc")
395413
edit_menu.addAction(clear_select_action)
396414

415+
self.add_tag_to_selected_action = QAction(menu_bar)
416+
Translations.translate_qobject(
417+
self.add_tag_to_selected_action, "select.add_tag_to_selected"
418+
)
419+
self.add_tag_to_selected_action.triggered.connect(self.add_tag_modal.show)
420+
self.add_tag_to_selected_action.setShortcut(
421+
QtCore.QKeyCombination(
422+
QtCore.Qt.KeyboardModifier(
423+
QtCore.Qt.KeyboardModifier.ControlModifier
424+
^ QtCore.Qt.KeyboardModifier.ShiftModifier
425+
),
426+
QtCore.Qt.Key.Key_T,
427+
)
428+
)
429+
self.add_tag_to_selected_action.setToolTip("Ctrl+Shift+T")
430+
self.add_tag_to_selected_action.setEnabled(False)
431+
edit_menu.addAction(self.add_tag_to_selected_action)
432+
397433
edit_menu.addSeparator()
398434

399435
manage_file_extensions_action = QAction(menu_bar)
@@ -551,6 +587,7 @@ def create_about_modal():
551587
self.open_library(path_result.library_path)
552588

553589
# check ffmpeg and show warning if not
590+
# NOTE: Does this need to use self?
554591
self.ffmpeg_checker = FfmpegChecker()
555592
if not self.ffmpeg_checker.installed():
556593
self.ffmpeg_checker.show_warning()
@@ -705,9 +742,12 @@ def close_library(self, is_shutdown: bool = False):
705742

706743
self.preview_panel.update_widgets()
707744
self.main_window.toggle_landing_page(enabled=True)
708-
709745
self.main_window.pagination.setHidden(True)
710746

747+
# NOTE: Doesn't try to disable during tests
748+
if self.add_tag_to_selected_action:
749+
self.add_tag_to_selected_action.setEnabled(False)
750+
711751
end_time = time.time()
712752
self.main_window.statusbar.showMessage(
713753
Translations.translate_formatted(
@@ -760,16 +800,22 @@ def select_all_action_callback(self):
760800
item.thumb_button.set_selected(True)
761801

762802
self.set_macro_menu_viability()
803+
self.set_add_to_selected_visibility()
763804
self.preview_panel.update_widgets(update_preview=False)
764805

765806
def clear_select_action_callback(self):
766807
self.selected.clear()
808+
self.set_add_to_selected_visibility()
767809
for item in self.item_thumbs:
768810
item.thumb_button.set_selected(False)
769811

770812
self.set_macro_menu_viability()
771813
self.preview_panel.update_widgets()
772814

815+
def add_tags_to_selected_callback(self, tag_ids: list[int]):
816+
for entry_id in self.selected:
817+
self.lib.add_tags_to_entry(entry_id, tag_ids)
818+
773819
def show_tag_database(self):
774820
self.modal = PanelModal(
775821
widget=TagDatabasePanel(self.lib),
@@ -1110,11 +1156,21 @@ def toggle_item_selection(self, item_id: int, append: bool, bridge: bool):
11101156
it.thumb_button.set_selected(False)
11111157

11121158
self.set_macro_menu_viability()
1159+
self.set_add_to_selected_visibility()
11131160
self.preview_panel.update_widgets()
11141161

11151162
def set_macro_menu_viability(self):
11161163
self.autofill_action.setDisabled(not self.selected)
11171164

1165+
def set_add_to_selected_visibility(self):
1166+
if not self.add_tag_to_selected_action:
1167+
return
1168+
1169+
if self.selected:
1170+
self.add_tag_to_selected_action.setEnabled(True)
1171+
else:
1172+
self.add_tag_to_selected_action.setEnabled(False)
1173+
11181174
def update_completions_list(self, text: str) -> None:
11191175
matches = re.search(
11201176
r"((?:.* )?)(mediatype|filetype|path|tag|tag_id):(\"?[A-Za-z0-9\ \t]+\"?)?", text
@@ -1478,6 +1534,7 @@ def init_library(self, path: Path, open_status: LibraryStatus):
14781534
self.main_window.setAcceptDrops(True)
14791535

14801536
self.selected.clear()
1537+
self.set_add_to_selected_visibility()
14811538
self.preview_panel.update_widgets()
14821539

14831540
# page (re)rendering, extract eventually

tagstudio/src/qt/widgets/tag_box.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import structlog
99
from PySide6.QtCore import Signal
1010
from src.core.library import Tag
11-
from src.core.library.alchemy.enums import FilterState
1211
from src.qt.flowlayout import FlowLayout
1312
from src.qt.modals.build_tag import BuildTagPanel
1413
from src.qt.widgets.fields import FieldWidget
@@ -53,12 +52,7 @@ def set_tags(self, tags: typing.Iterable[Tag]):
5352

5453
for tag in tags_:
5554
tag_widget = TagWidget(tag, library=self.driver.lib, has_edit=True, has_remove=True)
56-
tag_widget.on_click.connect(
57-
lambda tag_id=tag.id: (
58-
self.driver.main_window.searchField.setText(f"tag_id:{tag_id}"),
59-
self.driver.filter_items(FilterState.from_tag_id(tag_id)),
60-
)
61-
)
55+
tag_widget.on_click.connect(lambda t=tag: self.edit_tag(t))
6256

6357
tag_widget.on_remove.connect(
6458
lambda tag_id=tag.id: (

0 commit comments

Comments
 (0)