anki/qt/aqt/exporting.py

192 lines
6.7 KiB
Python
Raw Normal View History

2019-02-05 04:59:03 +01:00
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from __future__ import annotations
import os
import re
2019-12-20 10:19:03 +01:00
import time
2020-03-06 05:19:25 +01:00
from concurrent.futures import Future
2020-02-09 07:37:50 +01:00
from typing import List, Optional
2019-12-20 10:19:03 +01:00
import aqt
2020-01-15 04:49:26 +01:00
from anki import hooks
2021-03-23 10:36:52 +01:00
from anki.cards import CardID
2021-03-23 10:53:47 +01:00
from anki.decks import DeckID
from anki.exporting import Exporter, exporters
2019-12-20 10:19:03 +01:00
from aqt.qt import *
from aqt.utils import (
checkInvalidFilename,
disable_help_button,
getSaveFile,
showWarning,
tooltip,
tr,
)
2019-12-20 10:19:03 +01:00
class ExportDialog(QDialog):
2020-02-25 08:56:46 +01:00
def __init__(
self,
mw: aqt.main.AnkiQt,
2021-03-23 10:53:47 +01:00
did: Optional[DeckID] = None,
2021-03-23 10:36:52 +01:00
cids: Optional[List[CardID]] = None,
2020-02-25 08:56:46 +01:00
):
QDialog.__init__(self, mw, Qt.Window)
self.mw = mw
2020-03-06 05:03:23 +01:00
self.col = mw.col.weakref()
self.frm = aqt.forms.exporting.Ui_ExportDialog()
self.frm.setupUi(self)
self.exporter: Optional[Exporter] = None
2020-02-09 07:37:50 +01:00
self.cids = cids
disable_help_button(self)
2014-06-20 02:13:12 +02:00
self.setup(did)
self.exec_()
2021-03-23 10:53:47 +01:00
def setup(self, did: Optional[DeckID]) -> None:
self.exporters = exporters(self.col)
# if a deck specified, start with .apkg type selected
idx = 0
2020-02-09 07:19:37 +01:00
if did or self.cids:
2019-12-23 01:34:10 +01:00
for c, (k, e) in enumerate(self.exporters):
if e.ext == ".apkg":
idx = c
break
self.frm.format.insertItems(0, [e[0] for e in self.exporters])
self.frm.format.setCurrentIndex(idx)
qconnect(self.frm.format.activated, self.exporterChanged)
self.exporterChanged(idx)
# deck list
if self.cids is None:
2021-03-26 04:48:26 +01:00
self.decks = [tr.exporting_all_decks()]
self.decks.extend(d.name for d in self.col.decks.all_names_and_ids())
else:
2021-03-26 04:48:26 +01:00
self.decks = [tr.exporting_selected_notes()]
self.frm.deck.addItems(self.decks)
# save button
2021-03-26 04:48:26 +01:00
b = QPushButton(tr.exporting_export())
self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole)
2014-06-20 02:13:12 +02:00
# set default option if accessed through deck button
if did:
2019-12-23 01:34:10 +01:00
name = self.mw.col.decks.get(did)["name"]
2014-06-20 02:13:12 +02:00
index = self.frm.deck.findText(name)
self.frm.deck.setCurrentIndex(index)
def exporterChanged(self, idx: int) -> None:
self.exporter = self.exporters[idx][1](self.col)
self.isApkg = self.exporter.ext == ".apkg"
self.isVerbatim = getattr(self.exporter, "verbatim", False)
self.isTextNote = getattr(self.exporter, "includeTags", False)
self.frm.includeSched.setVisible(
2019-12-23 01:34:10 +01:00
getattr(self.exporter, "includeSched", None) is not None
)
self.frm.includeMedia.setVisible(
2019-12-23 01:34:10 +01:00
getattr(self.exporter, "includeMedia", None) is not None
)
self.frm.includeTags.setVisible(
2019-12-23 01:34:10 +01:00
getattr(self.exporter, "includeTags", None) is not None
)
2019-03-04 23:57:53 +01:00
html = getattr(self.exporter, "includeHTML", None)
if html is not None:
self.frm.includeHTML.setVisible(True)
self.frm.includeHTML.setChecked(html)
else:
self.frm.includeHTML.setVisible(False)
# show deck list?
self.frm.deck.setVisible(not self.isVerbatim)
def accept(self) -> None:
2019-12-23 01:34:10 +01:00
self.exporter.includeSched = self.frm.includeSched.isChecked()
self.exporter.includeMedia = self.frm.includeMedia.isChecked()
self.exporter.includeTags = self.frm.includeTags.isChecked()
self.exporter.includeHTML = self.frm.includeHTML.isChecked()
idx = self.frm.deck.currentIndex()
if self.cids is not None:
# Browser Selection
self.exporter.cids = self.cids
self.exporter.did = None
elif idx == 0:
# All decks
self.exporter.did = None
self.exporter.cids = None
else:
# Deck idx-1 in the list of decks
self.exporter.cids = None
name = self.decks[self.frm.deck.currentIndex()]
self.exporter.did = self.col.decks.id(name)
if self.isVerbatim:
2019-12-23 01:34:10 +01:00
name = time.strftime("-%Y-%m-%d@%H-%M-%S", time.localtime(time.time()))
2021-03-26 04:48:26 +01:00
deck_name = tr.exporting_collection() + name
else:
# Get deck name and remove invalid filename characters
deck_name = self.decks[self.frm.deck.currentIndex()]
2019-12-23 01:34:10 +01:00
deck_name = re.sub('[\\\\/?<>:*|"^]', "_", deck_name)
filename = f"{deck_name}{self.exporter.ext}"
if callable(self.exporter.key):
key_str = self.exporter.key(self.col)
else:
key_str = self.exporter.key
while 1:
2019-12-23 01:34:10 +01:00
file = getSaveFile(
2020-08-31 05:29:28 +02:00
self,
2021-03-26 04:48:26 +01:00
tr.actions_export(),
2020-08-31 05:29:28 +02:00
"export",
key_str,
self.exporter.ext,
fname=filename,
2019-12-23 01:34:10 +01:00
)
if not file:
return
if checkInvalidFilename(os.path.basename(file), dirsep=False):
continue
if os.path.commonprefix([self.mw.pm.base, file]) == self.mw.pm.base:
showWarning("Please choose a different export location.")
continue
break
self.hide()
if file:
2020-03-06 05:19:25 +01:00
# check we can write to file
try:
f = open(file, "wb")
f.close()
except OSError as e:
showWarning(tr.exporting_couldnt_save_file(val=str(e)))
else:
os.unlink(file)
2020-03-06 05:19:25 +01:00
# progress handler
def exported_media(cnt: int) -> None:
2020-03-06 05:19:25 +01:00
self.mw.taskman.run_on_main(
lambda: self.mw.progress.update(
label=tr.exporting_exported_media_file(count=cnt)
2019-12-23 01:34:10 +01:00
)
)
2020-03-06 05:19:25 +01:00
2021-02-01 14:28:21 +01:00
def do_export() -> None:
self.exporter.exportInto(file)
2020-03-06 05:19:25 +01:00
2021-02-01 14:28:21 +01:00
def on_done(future: Future) -> None:
self.mw.progress.finish()
2020-03-06 05:19:25 +01:00
hooks.media_files_did_export.remove(exported_media)
# raises if exporter failed
future.result()
self.on_export_finished()
self.mw.progress.start()
2020-03-06 05:19:25 +01:00
hooks.media_files_did_export.append(exported_media)
self.mw.taskman.run_in_background(do_export, on_done)
def on_export_finished(self) -> None:
2020-03-06 05:19:25 +01:00
if self.isVerbatim:
2021-03-26 04:48:26 +01:00
msg = tr.exporting_collection_exported()
2020-03-06 05:19:25 +01:00
self.mw.reopen()
else:
if self.isTextNote:
msg = tr.exporting_note_exported(count=self.exporter.count)
2020-03-06 05:19:25 +01:00
else:
msg = tr.exporting_card_exported(count=self.exporter.count)
2020-03-06 05:19:25 +01:00
tooltip(msg, period=3000)
QDialog.reject(self)