mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
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:
parent
85f034b144
commit
de3b1754fa
4 changed files with 36 additions and 11 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
url = self.lastContextMenuRequest().mediaUrl()
|
||||||
|
file_name = url.fileName()
|
||||||
|
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:
|
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())
|
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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue