Previously both Save to Library submenu and Unsave from Library showed simultaneously for saved posts. Now only the relevant action appears based on whether the post is already in the library. Also removed stale _current_post override on unsave — get_preview_post already resolves the right-clicked post via grid selection index. behavior change: browse grid context menu shows either Save or Unsave, never both.
249 lines
11 KiB
Python
249 lines
11 KiB
Python
"""Single-post and multi-select right-click context menus."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from PySide6.QtWidgets import QApplication, QMenu
|
|
|
|
if TYPE_CHECKING:
|
|
from .main_window import BooruApp
|
|
|
|
|
|
class ContextMenuHandler:
|
|
"""Builds and dispatches context menus for the thumbnail grid."""
|
|
|
|
def __init__(self, app: BooruApp) -> None:
|
|
self._app = app
|
|
|
|
@staticmethod
|
|
def _is_child_of_menu(action, menu) -> bool:
|
|
parent = action.parent()
|
|
while parent:
|
|
if parent == menu:
|
|
return True
|
|
parent = getattr(parent, 'parent', lambda: None)()
|
|
return False
|
|
|
|
def show_single(self, index: int, pos) -> None:
|
|
if index < 0 or index >= len(self._app._posts):
|
|
return
|
|
post = self._app._posts[index]
|
|
menu = QMenu(self._app)
|
|
|
|
open_browser = menu.addAction("Open in Browser")
|
|
open_default = menu.addAction("Open in Default App")
|
|
menu.addSeparator()
|
|
save_as = menu.addAction("Save As...")
|
|
|
|
from ..core.config import library_folders
|
|
save_lib_menu = None
|
|
save_lib_unsorted = None
|
|
save_lib_new = None
|
|
save_lib_folders = {}
|
|
unsave_lib = None
|
|
if self._app._post_actions.is_post_saved(post.id):
|
|
unsave_lib = menu.addAction("Unsave from Library")
|
|
else:
|
|
save_lib_menu = menu.addMenu("Save to Library")
|
|
save_lib_unsorted = save_lib_menu.addAction("Unfiled")
|
|
save_lib_menu.addSeparator()
|
|
for folder in library_folders():
|
|
a = save_lib_menu.addAction(folder)
|
|
save_lib_folders[id(a)] = folder
|
|
save_lib_menu.addSeparator()
|
|
save_lib_new = save_lib_menu.addAction("+ New Folder...")
|
|
copy_clipboard = menu.addAction("Copy File to Clipboard")
|
|
copy_url = menu.addAction("Copy Image URL")
|
|
copy_tags = menu.addAction("Copy Tags")
|
|
menu.addSeparator()
|
|
|
|
fav_action = None
|
|
bm_folder_actions: dict[int, str] = {}
|
|
bm_unfiled = None
|
|
bm_new = None
|
|
if self._app._post_actions.is_current_bookmarked(index):
|
|
fav_action = menu.addAction("Remove Bookmark")
|
|
else:
|
|
fav_menu = menu.addMenu("Bookmark as")
|
|
bm_unfiled = fav_menu.addAction("Unfiled")
|
|
fav_menu.addSeparator()
|
|
for folder in self._app._db.get_folders():
|
|
a = fav_menu.addAction(folder)
|
|
bm_folder_actions[id(a)] = folder
|
|
fav_menu.addSeparator()
|
|
bm_new = fav_menu.addAction("+ New Folder...")
|
|
menu.addSeparator()
|
|
bl_menu = menu.addMenu("Blacklist Tag")
|
|
if post.tag_categories:
|
|
for category, tags in post.tag_categories.items():
|
|
cat_menu = bl_menu.addMenu(category)
|
|
for tag in tags[:30]:
|
|
cat_menu.addAction(tag)
|
|
else:
|
|
for tag in post.tag_list[:30]:
|
|
bl_menu.addAction(tag)
|
|
bl_post_action = menu.addAction("Blacklist Post")
|
|
|
|
action = menu.exec(pos)
|
|
if not action:
|
|
return
|
|
|
|
if action == open_browser:
|
|
self._app._open_in_browser(post)
|
|
elif action == open_default:
|
|
self._app._open_in_default(post)
|
|
elif action == save_as:
|
|
self._app._post_actions.save_as(post)
|
|
elif action == save_lib_unsorted:
|
|
self._app._post_actions.save_to_library(post, None)
|
|
elif action == save_lib_new:
|
|
from PySide6.QtWidgets import QInputDialog, QMessageBox
|
|
name, ok = QInputDialog.getText(self._app, "New Folder", "Folder name:")
|
|
if ok and name.strip():
|
|
try:
|
|
from ..core.config import saved_folder_dir
|
|
saved_folder_dir(name.strip())
|
|
except ValueError as e:
|
|
QMessageBox.warning(self._app, "Invalid Folder Name", str(e))
|
|
return
|
|
self._app._post_actions.save_to_library(post, name.strip())
|
|
elif id(action) in save_lib_folders:
|
|
self._app._post_actions.save_to_library(post, save_lib_folders[id(action)])
|
|
elif action == unsave_lib:
|
|
self._app._post_actions.unsave_from_preview()
|
|
elif action == copy_clipboard:
|
|
self._app._copy_file_to_clipboard()
|
|
elif action == copy_url:
|
|
QApplication.clipboard().setText(post.file_url)
|
|
self._app._status.showMessage("URL copied")
|
|
elif action == copy_tags:
|
|
QApplication.clipboard().setText(post.tags)
|
|
self._app._status.showMessage("Tags copied")
|
|
elif fav_action is not None and action == fav_action:
|
|
self._app._post_actions.toggle_bookmark(index)
|
|
elif bm_unfiled is not None and action == bm_unfiled:
|
|
self._app._post_actions.toggle_bookmark(index, None)
|
|
elif bm_new is not None and action == bm_new:
|
|
from PySide6.QtWidgets import QInputDialog, QMessageBox
|
|
name, ok = QInputDialog.getText(self._app, "New Bookmark Folder", "Folder name:")
|
|
if ok and name.strip():
|
|
try:
|
|
self._app._db.add_folder(name.strip())
|
|
except ValueError as e:
|
|
QMessageBox.warning(self._app, "Invalid Folder Name", str(e))
|
|
return
|
|
self._app._post_actions.toggle_bookmark(index, name.strip())
|
|
elif id(action) in bm_folder_actions:
|
|
self._app._post_actions.toggle_bookmark(index, bm_folder_actions[id(action)])
|
|
elif self._is_child_of_menu(action, bl_menu):
|
|
tag = action.text()
|
|
self._app._db.add_blacklisted_tag(tag)
|
|
self._app._db.set_setting("blacklist_enabled", "1")
|
|
if self._app._preview._current_path and tag in post.tag_list:
|
|
from ..core.cache import cached_path_for
|
|
cp = str(cached_path_for(post.file_url))
|
|
if cp == self._app._preview._current_path:
|
|
self._app._preview.clear()
|
|
if self._app._popout_ctrl.window and self._app._popout_ctrl.window.isVisible():
|
|
self._app._popout_ctrl.window.stop_media()
|
|
self._app._status.showMessage(f"Blacklisted: {tag}")
|
|
self._app._search_ctrl.remove_blacklisted_from_grid(tag=tag)
|
|
elif action == bl_post_action:
|
|
self._app._db.add_blacklisted_post(post.file_url)
|
|
self._app._search_ctrl.remove_blacklisted_from_grid(post_url=post.file_url)
|
|
self._app._status.showMessage(f"Post #{post.id} blacklisted")
|
|
self._app._search_ctrl.do_search()
|
|
|
|
def show_multi(self, indices: list, pos) -> None:
|
|
posts = [self._app._posts[i] for i in indices if 0 <= i < len(self._app._posts)]
|
|
if not posts:
|
|
return
|
|
count = len(posts)
|
|
|
|
site_id = self._app._site_combo.currentData()
|
|
any_bookmarked = bool(site_id) and any(self._app._db.is_bookmarked(site_id, p.id) for p in posts)
|
|
any_unbookmarked = bool(site_id) and any(not self._app._db.is_bookmarked(site_id, p.id) for p in posts)
|
|
any_saved = any(self._app._post_actions.is_post_saved(p.id) for p in posts)
|
|
any_unsaved = any(not self._app._post_actions.is_post_saved(p.id) for p in posts)
|
|
|
|
menu = QMenu(self._app)
|
|
|
|
save_menu = None
|
|
save_unsorted = None
|
|
save_new = None
|
|
save_folder_actions: dict[int, str] = {}
|
|
if any_unsaved:
|
|
from ..core.config import library_folders
|
|
save_menu = menu.addMenu(f"Save All to Library ({count})")
|
|
save_unsorted = save_menu.addAction("Unfiled")
|
|
for folder in library_folders():
|
|
a = save_menu.addAction(folder)
|
|
save_folder_actions[id(a)] = folder
|
|
save_menu.addSeparator()
|
|
save_new = save_menu.addAction("+ New Folder...")
|
|
|
|
unsave_lib_all = None
|
|
if any_saved:
|
|
unsave_lib_all = menu.addAction(f"Unsave All from Library ({count})")
|
|
|
|
if (any_unsaved or any_saved) and (any_unbookmarked or any_bookmarked):
|
|
menu.addSeparator()
|
|
|
|
fav_all = None
|
|
if any_unbookmarked:
|
|
fav_all = menu.addAction(f"Bookmark All ({count})")
|
|
|
|
unfav_all = None
|
|
if any_bookmarked:
|
|
unfav_all = menu.addAction(f"Remove All Bookmarks ({count})")
|
|
|
|
if any_unsaved or any_saved or any_unbookmarked or any_bookmarked:
|
|
menu.addSeparator()
|
|
batch_dl = menu.addAction(f"Download All ({count})...")
|
|
copy_urls = menu.addAction("Copy All URLs")
|
|
|
|
action = menu.exec(pos)
|
|
if not action:
|
|
return
|
|
|
|
if fav_all is not None and action == fav_all:
|
|
self._app._post_actions.bulk_bookmark(indices, posts)
|
|
elif save_unsorted is not None and action == save_unsorted:
|
|
self._app._post_actions.bulk_save(indices, posts, None)
|
|
elif save_new is not None and action == save_new:
|
|
from PySide6.QtWidgets import QInputDialog, QMessageBox
|
|
name, ok = QInputDialog.getText(self._app, "New Folder", "Folder name:")
|
|
if ok and name.strip():
|
|
try:
|
|
from ..core.config import saved_folder_dir
|
|
saved_folder_dir(name.strip())
|
|
except ValueError as e:
|
|
QMessageBox.warning(self._app, "Invalid Folder Name", str(e))
|
|
return
|
|
self._app._post_actions.bulk_save(indices, posts, name.strip())
|
|
elif id(action) in save_folder_actions:
|
|
self._app._post_actions.bulk_save(indices, posts, save_folder_actions[id(action)])
|
|
elif unsave_lib_all is not None and action == unsave_lib_all:
|
|
self._app._post_actions.bulk_unsave(indices, posts)
|
|
elif action == batch_dl:
|
|
from .dialogs import select_directory
|
|
dest = select_directory(self._app, "Download to folder")
|
|
if dest:
|
|
self._app._post_actions.batch_download_posts(posts, dest)
|
|
elif unfav_all is not None and action == unfav_all:
|
|
if site_id:
|
|
for post in posts:
|
|
self._app._db.remove_bookmark(site_id, post.id)
|
|
for idx in indices:
|
|
if 0 <= idx < len(self._app._grid._thumbs):
|
|
self._app._grid._thumbs[idx].set_bookmarked(False)
|
|
self._app._grid._clear_multi()
|
|
self._app._status.showMessage(f"Removed {count} bookmarks")
|
|
if self._app._stack.currentIndex() == 1:
|
|
self._app._bookmarks_view.refresh()
|
|
elif action == copy_urls:
|
|
urls = "\n".join(p.file_url for p in posts)
|
|
QApplication.clipboard().setText(urls)
|
|
self._app._status.showMessage(f"Copied {count} URLs")
|