Add "open image" option to editor (#3431)

* Add "open image" option to editor

* Update qt/aqt/editor.py

Co-authored-by: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com>

* Update editor.py

* Remove unused import

* Fix "show in folder"

* Fix 'show in folder' on macOS

* Revert "Fix "show in folder""

This reverts commit cf2b33ee9422bcaf8d9e20bd4cce74e5061c13cf.

* Reimplement show_in_folder for Windows (dae)

- Avoid reusing call(), as the startupinfo we were passing in was
breaking the explorer invocation
- Attempt to bring explorer to the front after the window has been show,
as it otherwise appears under Anki (at least when running from source)

---------

Co-authored-by: Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com>
Co-authored-by: Damien Elmes <gpg@ankiweb.net>
This commit is contained in:
user1823 2024-10-04 16:21:55 +05:30 committed by GitHub
parent 85f034b144
commit de3b1754fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 36 additions and 11 deletions

View file

@ -36,6 +36,7 @@ editing-mathjax-chemistry = MathJax chemistry
editing-mathjax-inline = MathJax inline editing-mathjax-inline = MathJax inline
editing-mathjax-placeholder = Press { $accept } to accept, { $newline } for new line. editing-mathjax-placeholder = Press { $accept } to accept, { $newline } for new line.
editing-media = Media editing-media = Media
editing-open-image = Open image
editing-show-in-folder = Show in folder editing-show-in-folder = Show in folder
editing-ordered-list = Ordered list editing-ordered-list = Ordered list
editing-outdent = Decrease indent editing-outdent = Decrease indent

View file

@ -577,6 +577,10 @@ types-protobuf==5.27.0.20240626 \
# via # via
# -r requirements.dev.in # -r requirements.dev.in
# mypy-protobuf # mypy-protobuf
types-pywin32==306.0.0.20240822 \
--hash=sha256:31a16f7eaf711166e8aec50ee1ddf0f16b4512e19ecc92a019ae7a0860b64bad \
--hash=sha256:34d22b58aaa2cc86fe585b6e2e1eda88a60b010badea0e0e4a410ebe28744645
# via -r requirements.dev.in
types-requests==2.32.0.20240712 \ types-requests==2.32.0.20240712 \
--hash=sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358 \ --hash=sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358 \
--hash=sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3 --hash=sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3

View file

@ -37,7 +37,7 @@ from anki.httpclient import HttpClient
from anki.models import NotetypeId, StockNotetype from anki.models import NotetypeId, StockNotetype
from anki.notes import Note, NoteFieldsCheckResult, NoteId from anki.notes import Note, NoteFieldsCheckResult, NoteId
from anki.utils import checksum, is_lin, is_mac, is_win, namedtmp from anki.utils import checksum, is_lin, is_mac, is_win, namedtmp
from aqt import AnkiQt, colors, gui_hooks, mw from aqt import AnkiQt, colors, gui_hooks
from aqt.operations import QueryOp from aqt.operations import QueryOp
from aqt.operations.note import update_note from aqt.operations.note import update_note
from aqt.operations.notetype import update_notetype_legacy from aqt.operations.notetype import update_notetype_legacy
@ -49,13 +49,14 @@ from aqt.utils import (
KeyboardModifiersPressed, KeyboardModifiersPressed,
disable_help_button, disable_help_button,
getFile, getFile,
openFolder,
openHelp, openHelp,
qtMenuShortcutWorkaround, qtMenuShortcutWorkaround,
restoreGeom, restoreGeom,
saveGeom, saveGeom,
shortcut, shortcut,
show_in_folder,
showInfo, showInfo,
showinFolder,
showWarning, showWarning,
tooltip, tooltip,
tr, tr,
@ -1592,7 +1593,7 @@ class EditorWebView(AnkiWebView):
a = m.addAction(tr.editing_paste()) a = m.addAction(tr.editing_paste())
qconnect(a.triggered, self.onPaste) qconnect(a.triggered, self.onPaste)
if self._opened_context_menu_on_image(): if self._opened_context_menu_on_image():
self._add_image_menu(AnkiWebView(self), m) self._add_image_menu(m)
gui_hooks.editor_will_show_context_menu(self, m) gui_hooks.editor_will_show_context_menu(self, m)
m.popup(QCursor.pos()) m.popup(QCursor.pos())
@ -1604,16 +1605,19 @@ class EditorWebView(AnkiWebView):
a = menu.addAction(tr.actions_copy()) a = menu.addAction(tr.actions_copy())
qconnect(a.triggered, self.onCopy) qconnect(a.triggered, self.onCopy)
def _add_image_menu(self, webview: AnkiWebView, menu: QMenu) -> None: def _add_image_menu(self, menu: QMenu) -> None:
a = menu.addAction(tr.editing_copy_image()) a = menu.addAction(tr.editing_copy_image())
qconnect(a.triggered, self.on_copy_image) qconnect(a.triggered, self.on_copy_image)
if is_win or is_mac: url = self.lastContextMenuRequest().mediaUrl()
url = webview.lastContextMenuRequest().mediaUrl()
file_name = url.fileName() file_name = url.fileName()
path = os.path.join(mw.col.media.dir(), file_name) path = os.path.join(self.editor.mw.col.media.dir(), file_name)
a = menu.addAction(tr.editing_open_image())
qconnect(a.triggered, lambda: openFolder(path))
if is_win or is_mac:
a = menu.addAction(tr.editing_show_in_folder()) a = menu.addAction(tr.editing_show_in_folder())
qconnect(a.triggered, lambda: showinFolder(path)) qconnect(a.triggered, lambda: show_in_folder(path))
# QFont returns "Kozuka Gothic Pro L" but WebEngine expects "Kozuka Gothic Pro Light" # QFont returns "Kozuka Gothic Pro L" but WebEngine expects "Kozuka Gothic Pro Light"

View file

@ -886,14 +886,14 @@ def openFolder(path: str) -> None:
QDesktopServices.openUrl(QUrl(f"file://{path}")) QDesktopServices.openUrl(QUrl(f"file://{path}"))
def showinFolder(path: str) -> None: def show_in_folder(path: str) -> None:
if is_win: if is_win:
call(["explorer", "/select,", f"file://{path}"]) _show_in_folder_win32(path)
elif is_mac: elif is_mac:
script = f""" script = f"""
tell application "Finder" tell application "Finder"
activate activate
select POSIX file '{path}' select POSIX file "{path}"
end tell end tell
""" """
call(osascript_to_args(script)) call(osascript_to_args(script))
@ -903,6 +903,22 @@ def showinFolder(path: str) -> None:
QDesktopServices.openUrl(QUrl(f"file://{path}")) QDesktopServices.openUrl(QUrl(f"file://{path}"))
def _show_in_folder_win32(path: str) -> None:
import win32con # pylint: disable=import-error
import win32gui # pylint: disable=import-error
from aqt import mw
def focus_explorer():
hwnd = win32gui.FindWindow("CabinetWClass", None)
if hwnd:
win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
win32gui.SetForegroundWindow(hwnd)
subprocess.run(["explorer", f"/select,{path}"], check=False)
mw.progress.single_shot(500, focus_explorer)
def osascript_to_args(script: str): def osascript_to_args(script: str):
args = [ args = [
item item