From 02d25669983e379a0b57dcdea5996b2367d2f2c5 Mon Sep 17 00:00:00 2001 From: user1823 <92206575+user1823@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:08:44 +0530 Subject: [PATCH] Add an option to show image from editor in folder (#3412) * Add "Show in folder" option to images in editor Credits: @abdnh's Reveal in File Manager add-on (https://github.com/abdnh/anki-misc/tree/master/reveal_in_file_manager) * Refactor --- ftl/core/editing.ftl | 1 + qt/aqt/editor.py | 41 ++++++++++++++++++++++++----------------- qt/aqt/utils.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/ftl/core/editing.ftl b/ftl/core/editing.ftl index 5c9b766f5..2da97d539 100644 --- a/ftl/core/editing.ftl +++ b/ftl/core/editing.ftl @@ -36,6 +36,7 @@ editing-mathjax-chemistry = MathJax chemistry editing-mathjax-inline = MathJax inline editing-mathjax-placeholder = Press { $accept } to accept, { $newline } for new line. editing-media = Media +editing-show-in-folder = Show in folder editing-ordered-list = Ordered list editing-outdent = Decrease indent editing-paste = Paste diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 2c53a9f1c..522fec329 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -36,8 +36,8 @@ from anki.hooks import runFilter from anki.httpclient import HttpClient from anki.models import NotetypeId, StockNotetype from anki.notes import Note, NoteFieldsCheckResult, NoteId -from anki.utils import checksum, is_lin, is_win, namedtmp -from aqt import AnkiQt, colors, gui_hooks +from anki.utils import checksum, is_lin, is_mac, is_win, namedtmp +from aqt import AnkiQt, colors, gui_hooks, mw from aqt.operations import QueryOp from aqt.operations.note import update_note from aqt.operations.notetype import update_notetype_legacy @@ -55,6 +55,7 @@ from aqt.utils import ( saveGeom, shortcut, showInfo, + showinFolder, showWarning, tooltip, tr, @@ -1599,28 +1600,34 @@ class EditorWebView(AnkiWebView): def contextMenuEvent(self, evt: QContextMenuEvent) -> None: m = QMenu(self) - self._maybe_add_cut_action(m) - self._maybe_add_copy_action(m) + if self.hasSelection(): + self._add_cut_action(m) + self._add_copy_action(m) a = m.addAction(tr.editing_paste()) qconnect(a.triggered, self.onPaste) - self._maybe_add_copy_image_action(m) + if self._opened_context_menu_on_image(): + self._add_image_menu(AnkiWebView(self), m) gui_hooks.editor_will_show_context_menu(self, m) m.popup(QCursor.pos()) - def _maybe_add_cut_action(self, menu: QMenu) -> None: - if self.hasSelection(): - a = menu.addAction(tr.editing_cut()) - qconnect(a.triggered, self.onCut) + def _add_cut_action(self, menu: QMenu) -> None: + a = menu.addAction(tr.editing_cut()) + qconnect(a.triggered, self.onCut) - def _maybe_add_copy_action(self, menu: QMenu) -> None: - if self.hasSelection(): - a = menu.addAction(tr.actions_copy()) - qconnect(a.triggered, self.onCopy) + def _add_copy_action(self, menu: QMenu) -> None: + a = menu.addAction(tr.actions_copy()) + qconnect(a.triggered, self.onCopy) - def _maybe_add_copy_image_action(self, menu: QMenu) -> None: - if self._opened_context_menu_on_image(): - a = menu.addAction(tr.editing_copy_image()) - qconnect(a.triggered, self.on_copy_image) + def _add_image_menu(self, webview: AnkiWebView, menu: QMenu) -> None: + a = menu.addAction(tr.editing_copy_image()) + qconnect(a.triggered, self.on_copy_image) + + if is_win or is_mac: + url = webview.lastContextMenuRequest().mediaUrl() + file_name = url.fileName() + path = os.path.join(mw.col.media.dir(), file_name) + a = menu.addAction(tr.editing_show_in_folder()) + qconnect(a.triggered, lambda: showinFolder(path)) # QFont returns "Kozuka Gothic Pro L" but WebEngine expects "Kozuka Gothic Pro Light" diff --git a/qt/aqt/utils.py b/qt/aqt/utils.py index 8d7774555..b265b2f6e 100644 --- a/qt/aqt/utils.py +++ b/qt/aqt/utils.py @@ -21,6 +21,7 @@ from anki._legacy import DeprecatedNamesMixinForModule from anki.collection import Collection, HelpPage from anki.lang import TR, tr_legacyglobal # pylint: disable=unused-import from anki.utils import ( + call, invalid_filename, is_mac, is_win, @@ -885,6 +886,33 @@ def openFolder(path: str) -> None: QDesktopServices.openUrl(QUrl(f"file://{path}")) +def showinFolder(path: str) -> None: + if is_win: + call(["explorer", "/select,", f"file://{path}"]) + elif is_mac: + script = f""" + tell application "Finder" + activate + select POSIX file '{path}' + end tell + """ + call(osascript_to_args(script)) + else: + # Just open the file in any other platform + with no_bundled_libs(): + QDesktopServices.openUrl(QUrl(f"file://{path}")) + + +def osascript_to_args(script: str): + args = [ + item + for line in script.splitlines() + for item in ("-e", line.strip()) + if line.strip() + ] + return ["osascript"] + args + + def shortcut(key: str) -> str: if is_mac: return re.sub("(?i)ctrl", "Command", key)