diff --git a/ftl/qt/qt-accel.ftl b/ftl/qt/qt-accel.ftl
index 3ab54eb24..ba2888ea4 100644
--- a/ftl/qt/qt-accel.ftl
+++ b/ftl/qt/qt-accel.ftl
@@ -16,6 +16,7 @@ qt-accel-go = &Go
qt-accel-guide = &Guide
qt-accel-help = &Help
qt-accel-import = &Import...
+qt-accel-import-clipboard = Import from &Clipboard...
qt-accel-info = &Info...
qt-accel-invert-selection = &Invert Selection
qt-accel-next-card = &Next Card
diff --git a/qt/aqt/forms/main.ui b/qt/aqt/forms/main.ui
index bffc67ad0..69d687023 100644
--- a/qt/aqt/forms/main.ui
+++ b/qt/aqt/forms/main.ui
@@ -72,6 +72,7 @@
+
@@ -203,6 +204,14 @@
Ctrl+Shift+I
+
+
+ qt_accel_import_clipboard
+
+
+ Ctrl+Alt+Shift+I
+
+
qt_misc_study_deck
diff --git a/qt/aqt/import_export/importing.py b/qt/aqt/import_export/importing.py
index cb27c5e4b..696b1ee5a 100644
--- a/qt/aqt/import_export/importing.py
+++ b/qt/aqt/import_export/importing.py
@@ -5,6 +5,7 @@ from __future__ import annotations
import os
import re
+import tempfile
from abc import ABC, abstractmethod
from collections.abc import Callable
from itertools import chain
@@ -167,6 +168,36 @@ def prompt_for_file_then_import(mw: aqt.main.AnkiQt) -> None:
import_file(mw, path)
+def import_from_clipboard(mw: aqt.main.AnkiQt) -> None:
+ clipboard = QApplication.clipboard()
+
+ if clipboard is None:
+ showWarning("Clipboard not available.")
+ return
+
+ text = clipboard.text()
+
+ if not text:
+ showWarning("Clipboard is empty.")
+ return
+
+ try:
+ with tempfile.NamedTemporaryFile(
+ mode="w",
+ prefix="clipboard_",
+ suffix=".txt",
+ delete=False,
+ encoding="utf-8",
+ ) as f:
+ f.write(text)
+ temp_path = f.name
+
+ import_file(mw, temp_path)
+
+ except Exception as e:
+ showWarning(f"Failed to import from clipboard: {e}")
+
+
def get_file_path(mw: aqt.main.AnkiQt) -> str | None:
filter = without_unicode_isolation(
tr.importing_all_supported_formats(
diff --git a/qt/aqt/main.py b/qt/aqt/main.py
index c707d1b2a..55b038572 100644
--- a/qt/aqt/main.py
+++ b/qt/aqt/main.py
@@ -57,6 +57,7 @@ from aqt.import_export.exporting import ExportDialog
from aqt.import_export.importing import (
import_collection_package_op,
import_file,
+ import_from_clipboard,
prompt_for_file_then_import,
)
from aqt.legacy import install_pylib_legacy
@@ -1360,6 +1361,10 @@ title="{}" {}>{}""".format(
else:
aqt.importing.onImport(self)
+ def onImportFromClipboard(self) -> None:
+ """Import from clipboard text."""
+ import_from_clipboard(self)
+
def onExport(self, did: DeckId | None = None) -> None:
import aqt.exporting
@@ -1403,6 +1408,7 @@ title="{}" {}>{}""".format(
m.actionSwitchProfile.triggered, self.unloadProfileAndShowProfileManager
)
qconnect(m.actionImport.triggered, self.onImport)
+ qconnect(m.actionImportClipboard.triggered, self.onImportFromClipboard)
qconnect(m.actionExport.triggered, self.onExport)
qconnect(m.action_create_backup.triggered, self.on_create_backup_now)
qconnect(m.action_open_backup.triggered, self.onOpenBackup)