|
81 | 81 | from src.qt.modals.fix_unlinked import FixUnlinkedEntriesModal |
82 | 82 | from src.qt.modals.folders_to_tags import FoldersToTagsModal |
83 | 83 | from src.qt.modals.tag_database import TagDatabasePanel |
| 84 | +from src.qt.modals.tag_search import TagSearchPanel |
84 | 85 | from src.qt.resource_manager import ResourceManager |
85 | 86 | from src.qt.splash import Splash |
86 | 87 | from src.qt.translations import Translations |
@@ -132,6 +133,9 @@ class QtDriver(DriverMixin, QObject): |
132 | 133 | SIGTERM = Signal() |
133 | 134 |
|
134 | 135 | preview_panel: PreviewPanel |
| 136 | + tag_search_panel: TagSearchPanel |
| 137 | + add_tag_modal: PanelModal |
| 138 | + |
135 | 139 | lib: Library |
136 | 140 |
|
137 | 141 | def __init__(self, backend, args): |
@@ -199,6 +203,8 @@ def __init__(self, backend, args): |
199 | 203 | f"[Config] Thumbnail cache size limit: {format_size(CacheManager.size_limit)}", |
200 | 204 | ) |
201 | 205 |
|
| 206 | + self.add_tag_to_selected_action: QAction | None = None |
| 207 | + |
202 | 208 | def init_workers(self): |
203 | 209 | """Init workers for rendering thumbnails.""" |
204 | 210 | if not self.thumb_threads: |
@@ -270,6 +276,18 @@ def start(self) -> None: |
270 | 276 | icon.addFile(str(icon_path)) |
271 | 277 | app.setWindowIcon(icon) |
272 | 278 |
|
| 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 | + |
273 | 291 | menu_bar = QMenuBar(self.main_window) |
274 | 292 | self.main_window.setMenuBar(menu_bar) |
275 | 293 | menu_bar.setNativeMenuBar(True) |
@@ -394,6 +412,24 @@ def start(self) -> None: |
394 | 412 | clear_select_action.setToolTip("Esc") |
395 | 413 | edit_menu.addAction(clear_select_action) |
396 | 414 |
|
| 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 | + |
397 | 433 | edit_menu.addSeparator() |
398 | 434 |
|
399 | 435 | manage_file_extensions_action = QAction(menu_bar) |
@@ -551,6 +587,7 @@ def create_about_modal(): |
551 | 587 | self.open_library(path_result.library_path) |
552 | 588 |
|
553 | 589 | # check ffmpeg and show warning if not |
| 590 | + # NOTE: Does this need to use self? |
554 | 591 | self.ffmpeg_checker = FfmpegChecker() |
555 | 592 | if not self.ffmpeg_checker.installed(): |
556 | 593 | self.ffmpeg_checker.show_warning() |
@@ -705,9 +742,12 @@ def close_library(self, is_shutdown: bool = False): |
705 | 742 |
|
706 | 743 | self.preview_panel.update_widgets() |
707 | 744 | self.main_window.toggle_landing_page(enabled=True) |
708 | | - |
709 | 745 | self.main_window.pagination.setHidden(True) |
710 | 746 |
|
| 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 | + |
711 | 751 | end_time = time.time() |
712 | 752 | self.main_window.statusbar.showMessage( |
713 | 753 | Translations.translate_formatted( |
@@ -760,16 +800,22 @@ def select_all_action_callback(self): |
760 | 800 | item.thumb_button.set_selected(True) |
761 | 801 |
|
762 | 802 | self.set_macro_menu_viability() |
| 803 | + self.set_add_to_selected_visibility() |
763 | 804 | self.preview_panel.update_widgets(update_preview=False) |
764 | 805 |
|
765 | 806 | def clear_select_action_callback(self): |
766 | 807 | self.selected.clear() |
| 808 | + self.set_add_to_selected_visibility() |
767 | 809 | for item in self.item_thumbs: |
768 | 810 | item.thumb_button.set_selected(False) |
769 | 811 |
|
770 | 812 | self.set_macro_menu_viability() |
771 | 813 | self.preview_panel.update_widgets() |
772 | 814 |
|
| 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 | + |
773 | 819 | def show_tag_database(self): |
774 | 820 | self.modal = PanelModal( |
775 | 821 | widget=TagDatabasePanel(self.lib), |
@@ -1110,11 +1156,21 @@ def toggle_item_selection(self, item_id: int, append: bool, bridge: bool): |
1110 | 1156 | it.thumb_button.set_selected(False) |
1111 | 1157 |
|
1112 | 1158 | self.set_macro_menu_viability() |
| 1159 | + self.set_add_to_selected_visibility() |
1113 | 1160 | self.preview_panel.update_widgets() |
1114 | 1161 |
|
1115 | 1162 | def set_macro_menu_viability(self): |
1116 | 1163 | self.autofill_action.setDisabled(not self.selected) |
1117 | 1164 |
|
| 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 | + |
1118 | 1174 | def update_completions_list(self, text: str) -> None: |
1119 | 1175 | matches = re.search( |
1120 | 1176 | 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): |
1478 | 1534 | self.main_window.setAcceptDrops(True) |
1479 | 1535 |
|
1480 | 1536 | self.selected.clear() |
| 1537 | + self.set_add_to_selected_visibility() |
1481 | 1538 | self.preview_panel.update_widgets() |
1482 | 1539 |
|
1483 | 1540 | # page (re)rendering, extract eventually |
|
0 commit comments