mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
add a bunch of return types
This commit is contained in:
parent
f15715fb07
commit
a56b09b987
41 changed files with 359 additions and 338 deletions
|
@ -10,7 +10,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Any, Callable, Dict, Optional, Union
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import anki.lang
|
import anki.lang
|
||||||
from anki import version as _version
|
from anki import version as _version
|
||||||
|
@ -102,10 +102,10 @@ class DialogManager:
|
||||||
self._dialogs[name][1] = instance
|
self._dialogs[name][1] = instance
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def markClosed(self, name: str):
|
def markClosed(self, name: str) -> None:
|
||||||
self._dialogs[name] = [self._dialogs[name][0], None]
|
self._dialogs[name] = [self._dialogs[name][0], None]
|
||||||
|
|
||||||
def allClosed(self):
|
def allClosed(self) -> bool:
|
||||||
return not any(x[1] for x in self._dialogs.values())
|
return not any(x[1] for x in self._dialogs.values())
|
||||||
|
|
||||||
def closeAll(self, onsuccess: Callable[[], None]) -> Optional[bool]:
|
def closeAll(self, onsuccess: Callable[[], None]) -> Optional[bool]:
|
||||||
|
@ -119,7 +119,7 @@ class DialogManager:
|
||||||
if not instance:
|
if not instance:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def callback():
|
def callback() -> None:
|
||||||
if self.allClosed():
|
if self.allClosed():
|
||||||
onsuccess()
|
onsuccess()
|
||||||
else:
|
else:
|
||||||
|
@ -189,12 +189,12 @@ def setupLangAndBackend(
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# add _ and ngettext globals used by legacy code
|
# add _ and ngettext globals used by legacy code
|
||||||
def fn__(arg):
|
def fn__(arg) -> None:
|
||||||
print("".join(traceback.format_stack()[-2]))
|
print("".join(traceback.format_stack()[-2]))
|
||||||
print("_ global will break in the future; please see anki/lang.py")
|
print("_ global will break in the future; please see anki/lang.py")
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
def fn_ngettext(a, b, c):
|
def fn_ngettext(a, b, c) -> None:
|
||||||
print("".join(traceback.format_stack()[-2]))
|
print("".join(traceback.format_stack()[-2]))
|
||||||
print("ngettext global will break in the future; please see anki/lang.py")
|
print("ngettext global will break in the future; please see anki/lang.py")
|
||||||
return b
|
return b
|
||||||
|
@ -244,11 +244,11 @@ class AnkiApp(QApplication):
|
||||||
KEY = "anki" + checksum(getpass.getuser())
|
KEY = "anki" + checksum(getpass.getuser())
|
||||||
TMOUT = 30000
|
TMOUT = 30000
|
||||||
|
|
||||||
def __init__(self, argv):
|
def __init__(self, argv) -> None:
|
||||||
QApplication.__init__(self, argv)
|
QApplication.__init__(self, argv)
|
||||||
self._argv = argv
|
self._argv = argv
|
||||||
|
|
||||||
def secondInstance(self):
|
def secondInstance(self) -> bool:
|
||||||
# we accept only one command line argument. if it's missing, send
|
# we accept only one command line argument. if it's missing, send
|
||||||
# a blank screen to just raise the existing window
|
# a blank screen to just raise the existing window
|
||||||
opts, args = parseArgs(self._argv)
|
opts, args = parseArgs(self._argv)
|
||||||
|
@ -267,7 +267,7 @@ class AnkiApp(QApplication):
|
||||||
self._srv.listen(self.KEY)
|
self._srv.listen(self.KEY)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def sendMsg(self, txt):
|
def sendMsg(self, txt) -> bool:
|
||||||
sock = QLocalSocket(self)
|
sock = QLocalSocket(self)
|
||||||
sock.connectToServer(self.KEY, QIODevice.WriteOnly)
|
sock.connectToServer(self.KEY, QIODevice.WriteOnly)
|
||||||
if not sock.waitForConnected(self.TMOUT):
|
if not sock.waitForConnected(self.TMOUT):
|
||||||
|
@ -286,7 +286,7 @@ class AnkiApp(QApplication):
|
||||||
sock.disconnectFromServer()
|
sock.disconnectFromServer()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def onRecv(self):
|
def onRecv(self) -> None:
|
||||||
sock = self._srv.nextPendingConnection()
|
sock = self._srv.nextPendingConnection()
|
||||||
if not sock.waitForReadyRead(self.TMOUT):
|
if not sock.waitForReadyRead(self.TMOUT):
|
||||||
sys.stderr.write(sock.errorString())
|
sys.stderr.write(sock.errorString())
|
||||||
|
@ -298,14 +298,14 @@ class AnkiApp(QApplication):
|
||||||
# OS X file/url handler
|
# OS X file/url handler
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def event(self, evt):
|
def event(self, evt) -> bool:
|
||||||
if evt.type() == QEvent.FileOpen:
|
if evt.type() == QEvent.FileOpen:
|
||||||
self.appMsg.emit(evt.file() or "raise") # type: ignore
|
self.appMsg.emit(evt.file() or "raise") # type: ignore
|
||||||
return True
|
return True
|
||||||
return QApplication.event(self, evt)
|
return QApplication.event(self, evt)
|
||||||
|
|
||||||
|
|
||||||
def parseArgs(argv):
|
def parseArgs(argv) -> Tuple[argparse.Namespace, List[str]]:
|
||||||
"Returns (opts, args)."
|
"Returns (opts, args)."
|
||||||
# py2app fails to strip this in some instances, then anki dies
|
# py2app fails to strip this in some instances, then anki dies
|
||||||
# as there's no such profile
|
# as there's no such profile
|
||||||
|
@ -330,7 +330,7 @@ def parseArgs(argv):
|
||||||
return parser.parse_known_args(argv[1:])
|
return parser.parse_known_args(argv[1:])
|
||||||
|
|
||||||
|
|
||||||
def setupGL(pm):
|
def setupGL(pm) -> None:
|
||||||
if isMac:
|
if isMac:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -343,7 +343,7 @@ def setupGL(pm):
|
||||||
ctypes.CDLL("libGL.so.1", ctypes.RTLD_GLOBAL)
|
ctypes.CDLL("libGL.so.1", ctypes.RTLD_GLOBAL)
|
||||||
|
|
||||||
# catch opengl errors
|
# catch opengl errors
|
||||||
def msgHandler(category, ctx, msg):
|
def msgHandler(category, ctx, msg) -> None:
|
||||||
if category == QtDebugMsg:
|
if category == QtDebugMsg:
|
||||||
category = "debug"
|
category = "debug"
|
||||||
elif category == QtInfoMsg:
|
elif category == QtInfoMsg:
|
||||||
|
@ -400,7 +400,7 @@ def setupGL(pm):
|
||||||
PROFILE_CODE = os.environ.get("ANKI_PROFILE_CODE")
|
PROFILE_CODE = os.environ.get("ANKI_PROFILE_CODE")
|
||||||
|
|
||||||
|
|
||||||
def write_profile_results():
|
def write_profile_results() -> None:
|
||||||
|
|
||||||
profiler.disable()
|
profiler.disable()
|
||||||
profiler.dump_stats("anki.prof")
|
profiler.dump_stats("anki.prof")
|
||||||
|
@ -408,7 +408,7 @@ def write_profile_results():
|
||||||
print("use 'bazel run qt:profile' to explore")
|
print("use 'bazel run qt:profile' to explore")
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run() -> None:
|
||||||
try:
|
try:
|
||||||
_run()
|
_run()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -420,7 +420,7 @@ def run():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _run(argv=None, exec=True):
|
def _run(argv=None, exec=True) -> Optional[AnkiApp]:
|
||||||
"""Start AnkiQt application or reuse an existing instance if one exists.
|
"""Start AnkiQt application or reuse an existing instance if one exists.
|
||||||
|
|
||||||
If the function is invoked with exec=False, the AnkiQt will not enter
|
If the function is invoked with exec=False, the AnkiQt will not enter
|
||||||
|
@ -441,12 +441,12 @@ def _run(argv=None, exec=True):
|
||||||
|
|
||||||
if opts.version:
|
if opts.version:
|
||||||
print(f"Anki {appVersion}")
|
print(f"Anki {appVersion}")
|
||||||
return
|
return None
|
||||||
elif opts.syncserver:
|
elif opts.syncserver:
|
||||||
from anki.syncserver import serve
|
from anki.syncserver import serve
|
||||||
|
|
||||||
serve()
|
serve()
|
||||||
return
|
return None
|
||||||
|
|
||||||
if PROFILE_CODE:
|
if PROFILE_CODE:
|
||||||
|
|
||||||
|
@ -465,7 +465,7 @@ def _run(argv=None, exec=True):
|
||||||
except AnkiRestart as error:
|
except AnkiRestart as error:
|
||||||
if error.exitcode:
|
if error.exitcode:
|
||||||
sys.exit(error.exitcode)
|
sys.exit(error.exitcode)
|
||||||
return
|
return None
|
||||||
except:
|
except:
|
||||||
# will handle below
|
# will handle below
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -500,7 +500,7 @@ def _run(argv=None, exec=True):
|
||||||
app = AnkiApp(argv)
|
app = AnkiApp(argv)
|
||||||
if app.secondInstance():
|
if app.secondInstance():
|
||||||
# we've signaled the primary instance, so we should close
|
# we've signaled the primary instance, so we should close
|
||||||
return
|
return None
|
||||||
|
|
||||||
if not pm:
|
if not pm:
|
||||||
QMessageBox.critical(
|
QMessageBox.critical(
|
||||||
|
@ -508,7 +508,7 @@ def _run(argv=None, exec=True):
|
||||||
tr(TR.QT_MISC_ERROR),
|
tr(TR.QT_MISC_ERROR),
|
||||||
tr(TR.PROFILES_COULD_NOT_CREATE_DATA_FOLDER),
|
tr(TR.PROFILES_COULD_NOT_CREATE_DATA_FOLDER),
|
||||||
)
|
)
|
||||||
return
|
return None
|
||||||
|
|
||||||
# disable icons on mac; this must be done before window created
|
# disable icons on mac; this must be done before window created
|
||||||
if isMac:
|
if isMac:
|
||||||
|
@ -548,7 +548,7 @@ def _run(argv=None, exec=True):
|
||||||
tr(TR.QT_MISC_ERROR),
|
tr(TR.QT_MISC_ERROR),
|
||||||
tr(TR.QT_MISC_NO_TEMP_FOLDER),
|
tr(TR.QT_MISC_NO_TEMP_FOLDER),
|
||||||
)
|
)
|
||||||
return
|
return None
|
||||||
|
|
||||||
if pmLoadResult.firstTime:
|
if pmLoadResult.firstTime:
|
||||||
pm.setDefaultLang(lang[0])
|
pm.setDefaultLang(lang[0])
|
||||||
|
@ -590,3 +590,5 @@ def _run(argv=None, exec=True):
|
||||||
|
|
||||||
if PROFILE_CODE:
|
if PROFILE_CODE:
|
||||||
write_profile_results()
|
write_profile_results()
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
|
@ -13,20 +13,20 @@ from aqt.utils import TR, disable_help_button, supportText, tooltip, tr
|
||||||
|
|
||||||
|
|
||||||
class ClosableQDialog(QDialog):
|
class ClosableQDialog(QDialog):
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
aqt.dialogs.markClosed("About")
|
aqt.dialogs.markClosed("About")
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
aqt.dialogs.markClosed("About")
|
aqt.dialogs.markClosed("About")
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
||||||
def closeWithCallback(self, callback):
|
def closeWithCallback(self, callback) -> None:
|
||||||
self.reject()
|
self.reject()
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
||||||
def show(mw):
|
def show(mw) -> QDialog:
|
||||||
dialog = ClosableQDialog(mw)
|
dialog = ClosableQDialog(mw)
|
||||||
disable_help_button(dialog)
|
disable_help_button(dialog)
|
||||||
mw.setupDialogGC(dialog)
|
mw.setupDialogGC(dialog)
|
||||||
|
@ -55,7 +55,7 @@ def show(mw):
|
||||||
modified = "mod"
|
modified = "mod"
|
||||||
return f"{name} ['{addon.dir_name}', {installed}, '{addon.human_version}', {modified}]"
|
return f"{name} ['{addon.dir_name}', {installed}, '{addon.human_version}', {modified}]"
|
||||||
|
|
||||||
def onCopy():
|
def onCopy() -> None:
|
||||||
addmgr = mw.addonManager
|
addmgr = mw.addonManager
|
||||||
active = []
|
active = []
|
||||||
activeids = []
|
activeids = []
|
||||||
|
|
|
@ -65,7 +65,7 @@ class AddCards(QDialog):
|
||||||
)
|
)
|
||||||
self.deckChooser = aqt.deckchooser.DeckChooser(self.mw, self.form.deckArea)
|
self.deckChooser = aqt.deckchooser.DeckChooser(self.mw, self.form.deckArea)
|
||||||
|
|
||||||
def helpRequested(self):
|
def helpRequested(self) -> None:
|
||||||
openHelp(HelpPage.ADDING_CARD_AND_NOTE)
|
openHelp(HelpPage.ADDING_CARD_AND_NOTE)
|
||||||
|
|
||||||
def setupButtons(self) -> None:
|
def setupButtons(self) -> None:
|
||||||
|
@ -161,7 +161,7 @@ class AddCards(QDialog):
|
||||||
gui_hooks.add_cards_will_show_history_menu(self, m)
|
gui_hooks.add_cards_will_show_history_menu(self, m)
|
||||||
m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
|
m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
|
||||||
|
|
||||||
def editHistory(self, nid):
|
def editHistory(self, nid) -> None:
|
||||||
self.mw.browser_search(SearchTerm(nid=nid))
|
self.mw.browser_search(SearchTerm(nid=nid))
|
||||||
|
|
||||||
def addNote(self, note) -> Optional[Note]:
|
def addNote(self, note) -> Optional[Note]:
|
||||||
|
@ -225,7 +225,7 @@ class AddCards(QDialog):
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def ifCanClose(self, onOk: Callable) -> None:
|
def ifCanClose(self, onOk: Callable) -> None:
|
||||||
def afterSave():
|
def afterSave() -> None:
|
||||||
ok = self.editor.fieldsAreBlank(self.previousNote) or askUser(
|
ok = self.editor.fieldsAreBlank(self.previousNote) or askUser(
|
||||||
tr(TR.ADDING_CLOSE_AND_LOSE_CURRENT_INPUT), defaultno=True
|
tr(TR.ADDING_CLOSE_AND_LOSE_CURRENT_INPUT), defaultno=True
|
||||||
)
|
)
|
||||||
|
@ -234,8 +234,8 @@ class AddCards(QDialog):
|
||||||
|
|
||||||
self.editor.saveNow(afterSave)
|
self.editor.saveNow(afterSave)
|
||||||
|
|
||||||
def closeWithCallback(self, cb):
|
def closeWithCallback(self, cb) -> None:
|
||||||
def doClose():
|
def doClose() -> None:
|
||||||
self._reject()
|
self._reject()
|
||||||
cb()
|
cb()
|
||||||
|
|
||||||
|
|
|
@ -605,7 +605,7 @@ class AddonManager:
|
||||||
def _addon_schema_path(self, dir: str) -> str:
|
def _addon_schema_path(self, dir: str) -> str:
|
||||||
return os.path.join(self.addonsFolder(dir), "config.schema.json")
|
return os.path.join(self.addonsFolder(dir), "config.schema.json")
|
||||||
|
|
||||||
def _addon_schema(self, dir: str):
|
def _addon_schema(self, dir: str) -> Any:
|
||||||
path = self._addon_schema_path(dir)
|
path = self._addon_schema_path(dir)
|
||||||
try:
|
try:
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Match, Optional
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
|
@ -140,7 +140,7 @@ class CardLayout(QDialog):
|
||||||
combo.setEnabled(not self._isCloze())
|
combo.setEnabled(not self._isCloze())
|
||||||
self.ignore_change_signals = False
|
self.ignore_change_signals = False
|
||||||
|
|
||||||
def _summarizedName(self, idx: int, tmpl: Dict):
|
def _summarizedName(self, idx: int, tmpl: Dict) -> str:
|
||||||
return "{}: {}: {} -> {}".format(
|
return "{}: {}: {} -> {}".format(
|
||||||
idx + 1,
|
idx + 1,
|
||||||
tmpl["name"],
|
tmpl["name"],
|
||||||
|
@ -284,7 +284,7 @@ class CardLayout(QDialog):
|
||||||
|
|
||||||
self.fill_fields_from_template()
|
self.fill_fields_from_template()
|
||||||
|
|
||||||
def on_search_changed(self, text: str):
|
def on_search_changed(self, text: str) -> None:
|
||||||
editor = self.tform.edit_area
|
editor = self.tform.edit_area
|
||||||
if not editor.find(text):
|
if not editor.find(text):
|
||||||
# try again from top
|
# try again from top
|
||||||
|
@ -294,7 +294,7 @@ class CardLayout(QDialog):
|
||||||
if not editor.find(text):
|
if not editor.find(text):
|
||||||
tooltip("No matches found.")
|
tooltip("No matches found.")
|
||||||
|
|
||||||
def on_search_next(self):
|
def on_search_next(self) -> None:
|
||||||
text = self.tform.search_edit.text()
|
text = self.tform.search_edit.text()
|
||||||
self.on_search_changed(text)
|
self.on_search_changed(text)
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ class CardLayout(QDialog):
|
||||||
self.fill_empty_action_toggled = not self.fill_empty_action_toggled
|
self.fill_empty_action_toggled = not self.fill_empty_action_toggled
|
||||||
self.on_preview_toggled()
|
self.on_preview_toggled()
|
||||||
|
|
||||||
def on_night_mode_action_toggled(self):
|
def on_night_mode_action_toggled(self) -> None:
|
||||||
self.night_mode_is_enabled = not self.night_mode_is_enabled
|
self.night_mode_is_enabled = not self.night_mode_is_enabled
|
||||||
self.on_preview_toggled()
|
self.on_preview_toggled()
|
||||||
|
|
||||||
|
@ -520,7 +520,7 @@ class CardLayout(QDialog):
|
||||||
txt = txt.replace("<hr id=answer>", "")
|
txt = txt.replace("<hr id=answer>", "")
|
||||||
hadHR = origLen != len(txt)
|
hadHR = origLen != len(txt)
|
||||||
|
|
||||||
def answerRepl(match):
|
def answerRepl(match: Match) -> str:
|
||||||
res = self.mw.reviewer.correct("exomple", "an example")
|
res = self.mw.reviewer.correct("exomple", "an example")
|
||||||
if hadHR:
|
if hadHR:
|
||||||
res = "<hr id=answer>" + res
|
res = "<hr id=answer>" + res
|
||||||
|
@ -556,14 +556,15 @@ class CardLayout(QDialog):
|
||||||
# Card operations
|
# Card operations
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def onRemove(self):
|
def onRemove(self) -> None:
|
||||||
if len(self.templates) < 2:
|
if len(self.templates) < 2:
|
||||||
return showInfo(tr(TR.CARD_TEMPLATES_AT_LEAST_ONE_CARD_TYPE_IS))
|
showInfo(tr(TR.CARD_TEMPLATES_AT_LEAST_ONE_CARD_TYPE_IS))
|
||||||
|
return
|
||||||
|
|
||||||
def get_count():
|
def get_count() -> int:
|
||||||
return self.mm.template_use_count(self.model["id"], self.ord)
|
return self.mm.template_use_count(self.model["id"], self.ord)
|
||||||
|
|
||||||
def on_done(fut):
|
def on_done(fut) -> None:
|
||||||
card_cnt = fut.result()
|
card_cnt = fut.result()
|
||||||
|
|
||||||
template = self.current_template()
|
template = self.current_template()
|
||||||
|
@ -593,7 +594,7 @@ class CardLayout(QDialog):
|
||||||
|
|
||||||
self.redraw_everything()
|
self.redraw_everything()
|
||||||
|
|
||||||
def onRename(self):
|
def onRename(self) -> None:
|
||||||
template = self.current_template()
|
template = self.current_template()
|
||||||
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=template["name"]).replace(
|
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=template["name"]).replace(
|
||||||
'"', ""
|
'"', ""
|
||||||
|
@ -604,7 +605,7 @@ class CardLayout(QDialog):
|
||||||
template["name"] = name
|
template["name"] = name
|
||||||
self.redraw_everything()
|
self.redraw_everything()
|
||||||
|
|
||||||
def onReorder(self):
|
def onReorder(self) -> None:
|
||||||
n = len(self.templates)
|
n = len(self.templates)
|
||||||
template = self.current_template()
|
template = self.current_template()
|
||||||
current_pos = self.templates.index(template) + 1
|
current_pos = self.templates.index(template) + 1
|
||||||
|
@ -629,7 +630,7 @@ class CardLayout(QDialog):
|
||||||
self.ord = new_idx
|
self.ord = new_idx
|
||||||
self.redraw_everything()
|
self.redraw_everything()
|
||||||
|
|
||||||
def _newCardName(self):
|
def _newCardName(self) -> str:
|
||||||
n = len(self.templates) + 1
|
n = len(self.templates) + 1
|
||||||
while 1:
|
while 1:
|
||||||
name = without_unicode_isolation(tr(TR.CARD_TEMPLATES_CARD, val=n))
|
name = without_unicode_isolation(tr(TR.CARD_TEMPLATES_CARD, val=n))
|
||||||
|
@ -638,7 +639,7 @@ class CardLayout(QDialog):
|
||||||
n += 1
|
n += 1
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def onAddCard(self):
|
def onAddCard(self) -> None:
|
||||||
cnt = self.mw.col.models.useCount(self.model)
|
cnt = self.mw.col.models.useCount(self.model)
|
||||||
txt = tr(TR.CARD_TEMPLATES_THIS_WILL_CREATE_CARD_PROCEED, count=cnt)
|
txt = tr(TR.CARD_TEMPLATES_THIS_WILL_CREATE_CARD_PROCEED, count=cnt)
|
||||||
if not askUser(txt):
|
if not askUser(txt):
|
||||||
|
@ -654,12 +655,12 @@ class CardLayout(QDialog):
|
||||||
self.ord = len(self.templates) - 1
|
self.ord = len(self.templates) - 1
|
||||||
self.redraw_everything()
|
self.redraw_everything()
|
||||||
|
|
||||||
def onFlip(self):
|
def onFlip(self) -> None:
|
||||||
old = self.current_template()
|
old = self.current_template()
|
||||||
self._flipQA(old, old)
|
self._flipQA(old, old)
|
||||||
self.redraw_everything()
|
self.redraw_everything()
|
||||||
|
|
||||||
def _flipQA(self, src, dst):
|
def _flipQA(self, src, dst) -> None:
|
||||||
m = re.match("(?s)(.+)<hr id=answer>(.+)", src["afmt"])
|
m = re.match("(?s)(.+)<hr id=answer>(.+)", src["afmt"])
|
||||||
if not m:
|
if not m:
|
||||||
showInfo(tr(TR.CARD_TEMPLATES_ANKI_COULDNT_FIND_THE_LINE_BETWEEN))
|
showInfo(tr(TR.CARD_TEMPLATES_ANKI_COULDNT_FIND_THE_LINE_BETWEEN))
|
||||||
|
@ -667,7 +668,6 @@ class CardLayout(QDialog):
|
||||||
self.change_tracker.mark_basic()
|
self.change_tracker.mark_basic()
|
||||||
dst["afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n%s" % src["qfmt"]
|
dst["afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n%s" % src["qfmt"]
|
||||||
dst["qfmt"] = m.group(2).strip()
|
dst["qfmt"] = m.group(2).strip()
|
||||||
return True
|
|
||||||
|
|
||||||
def onMore(self) -> None:
|
def onMore(self) -> None:
|
||||||
m = QMenu(self)
|
m = QMenu(self)
|
||||||
|
@ -728,7 +728,7 @@ class CardLayout(QDialog):
|
||||||
if key in t:
|
if key in t:
|
||||||
del t[key]
|
del t[key]
|
||||||
|
|
||||||
def onTargetDeck(self):
|
def onTargetDeck(self) -> None:
|
||||||
from aqt.tagedit import TagEdit
|
from aqt.tagedit import TagEdit
|
||||||
|
|
||||||
t = self.current_template()
|
t = self.current_template()
|
||||||
|
@ -760,7 +760,7 @@ class CardLayout(QDialog):
|
||||||
else:
|
else:
|
||||||
t["did"] = self.col.decks.id(te.text())
|
t["did"] = self.col.decks.id(te.text())
|
||||||
|
|
||||||
def onAddField(self):
|
def onAddField(self) -> None:
|
||||||
diag = QDialog(self)
|
diag = QDialog(self)
|
||||||
form = aqt.forms.addfield.Ui_Dialog()
|
form = aqt.forms.addfield.Ui_Dialog()
|
||||||
form.setupUi(diag)
|
form.setupUi(diag)
|
||||||
|
@ -780,7 +780,7 @@ class CardLayout(QDialog):
|
||||||
form.size.value(),
|
form.size.value(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _addField(self, field, font, size):
|
def _addField(self, field, font, size) -> None:
|
||||||
text = self.tform.edit_area.toPlainText()
|
text = self.tform.edit_area.toPlainText()
|
||||||
text += "\n<div style='font-family: %s; font-size: %spx;'>{{%s}}</div>\n" % (
|
text += "\n<div style='font-family: %s; font-size: %spx;'>{{%s}}</div>\n" % (
|
||||||
font,
|
font,
|
||||||
|
@ -795,10 +795,10 @@ class CardLayout(QDialog):
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def accept(self) -> None:
|
def accept(self) -> None:
|
||||||
def save():
|
def save() -> None:
|
||||||
self.mm.save(self.model)
|
self.mm.save(self.model)
|
||||||
|
|
||||||
def on_done(fut):
|
def on_done(fut) -> None:
|
||||||
try:
|
try:
|
||||||
fut.result()
|
fut.result()
|
||||||
except TemplateError as e:
|
except TemplateError as e:
|
||||||
|
@ -829,5 +829,5 @@ class CardLayout(QDialog):
|
||||||
self.rendered_card = None
|
self.rendered_card = None
|
||||||
self.mw = None
|
self.mw = None
|
||||||
|
|
||||||
def onHelp(self):
|
def onHelp(self) -> None:
|
||||||
openHelp(HelpPage.TEMPLATES)
|
openHelp(HelpPage.TEMPLATES)
|
||||||
|
|
|
@ -57,7 +57,7 @@ class CustomStudy(QDialog):
|
||||||
typeShow = False
|
typeShow = False
|
||||||
ok = tr(TR.CUSTOM_STUDY_OK)
|
ok = tr(TR.CUSTOM_STUDY_OK)
|
||||||
|
|
||||||
def plus(num):
|
def plus(num) -> str:
|
||||||
if num == 1000:
|
if num == 1000:
|
||||||
num = "1000+"
|
num = "1000+"
|
||||||
return "<b>" + str(num) + "</b>"
|
return "<b>" + str(num) + "</b>"
|
||||||
|
|
|
@ -9,7 +9,7 @@ from aqt.qt import *
|
||||||
from aqt.utils import showText, tooltip
|
from aqt.utils import showText, tooltip
|
||||||
|
|
||||||
|
|
||||||
def on_progress(mw: aqt.main.AnkiQt):
|
def on_progress(mw: aqt.main.AnkiQt) -> None:
|
||||||
progress = mw.col.latest_progress()
|
progress = mw.col.latest_progress()
|
||||||
if progress.kind != ProgressKind.DatabaseCheck:
|
if progress.kind != ProgressKind.DatabaseCheck:
|
||||||
return
|
return
|
||||||
|
@ -24,14 +24,14 @@ def on_progress(mw: aqt.main.AnkiQt):
|
||||||
|
|
||||||
|
|
||||||
def check_db(mw: aqt.AnkiQt) -> None:
|
def check_db(mw: aqt.AnkiQt) -> None:
|
||||||
def on_timer():
|
def on_timer() -> None:
|
||||||
on_progress(mw)
|
on_progress(mw)
|
||||||
|
|
||||||
timer = QTimer(mw)
|
timer = QTimer(mw)
|
||||||
qconnect(timer.timeout, on_timer)
|
qconnect(timer.timeout, on_timer)
|
||||||
timer.start(100)
|
timer.start(100)
|
||||||
|
|
||||||
def on_future_done(fut):
|
def on_future_done(fut) -> None:
|
||||||
timer.stop()
|
timer.stop()
|
||||||
ret, ok = fut.result()
|
ret, ok = fut.result()
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ from aqt.utils import TR, askUser, getOnlyText, openLink, shortcut, showWarning,
|
||||||
|
|
||||||
|
|
||||||
class DeckBrowserBottomBar:
|
class DeckBrowserBottomBar:
|
||||||
def __init__(self, deck_browser: DeckBrowser):
|
def __init__(self, deck_browser: DeckBrowser) -> None:
|
||||||
self.deck_browser = deck_browser
|
self.deck_browser = deck_browser
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,14 +51,14 @@ class DeckBrowser:
|
||||||
self.bottom = BottomBar(mw, mw.bottomWeb)
|
self.bottom = BottomBar(mw, mw.bottomWeb)
|
||||||
self.scrollPos = QPoint(0, 0)
|
self.scrollPos = QPoint(0, 0)
|
||||||
|
|
||||||
def show(self):
|
def show(self) -> None:
|
||||||
av_player.stop_and_clear_queue()
|
av_player.stop_and_clear_queue()
|
||||||
self.web.set_bridge_command(self._linkHandler, self)
|
self.web.set_bridge_command(self._linkHandler, self)
|
||||||
self._renderPage()
|
self._renderPage()
|
||||||
# redraw top bar for theme change
|
# redraw top bar for theme change
|
||||||
self.mw.toolbar.redraw()
|
self.mw.toolbar.redraw()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self) -> None:
|
||||||
self._renderPage()
|
self._renderPage()
|
||||||
|
|
||||||
# Event handlers
|
# Event handlers
|
||||||
|
@ -90,7 +90,7 @@ class DeckBrowser:
|
||||||
self._collapse(int(arg))
|
self._collapse(int(arg))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _selDeck(self, did):
|
def _selDeck(self, did) -> None:
|
||||||
self.mw.col.decks.select(did)
|
self.mw.col.decks.select(did)
|
||||||
self.mw.onOverview()
|
self.mw.onOverview()
|
||||||
|
|
||||||
|
@ -108,14 +108,14 @@ class DeckBrowser:
|
||||||
</center>
|
</center>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _renderPage(self, reuse=False):
|
def _renderPage(self, reuse=False) -> None:
|
||||||
if not reuse:
|
if not reuse:
|
||||||
self._dueTree = self.mw.col.sched.deck_due_tree()
|
self._dueTree = self.mw.col.sched.deck_due_tree()
|
||||||
self.__renderPage(None)
|
self.__renderPage(None)
|
||||||
return
|
return
|
||||||
self.web.evalWithCallback("window.pageYOffset", self.__renderPage)
|
self.web.evalWithCallback("window.pageYOffset", self.__renderPage)
|
||||||
|
|
||||||
def __renderPage(self, offset):
|
def __renderPage(self, offset) -> None:
|
||||||
content = DeckBrowserContent(
|
content = DeckBrowserContent(
|
||||||
tree=self._renderDeckTree(self._dueTree),
|
tree=self._renderDeckTree(self._dueTree),
|
||||||
stats=self._renderStats(),
|
stats=self._renderStats(),
|
||||||
|
@ -137,10 +137,10 @@ class DeckBrowser:
|
||||||
self._scrollToOffset(offset)
|
self._scrollToOffset(offset)
|
||||||
gui_hooks.deck_browser_did_render(self)
|
gui_hooks.deck_browser_did_render(self)
|
||||||
|
|
||||||
def _scrollToOffset(self, offset):
|
def _scrollToOffset(self, offset) -> None:
|
||||||
self.web.eval("$(function() { window.scrollTo(0, %d, 'instant'); });" % offset)
|
self.web.eval("$(function() { window.scrollTo(0, %d, 'instant'); });" % offset)
|
||||||
|
|
||||||
def _renderStats(self):
|
def _renderStats(self) -> str:
|
||||||
return '<div id="studiedToday"><span>{}</span></div>'.format(
|
return '<div id="studiedToday"><span>{}</span></div>'.format(
|
||||||
self.mw.col.studied_today(),
|
self.mw.col.studied_today(),
|
||||||
)
|
)
|
||||||
|
@ -170,7 +170,7 @@ class DeckBrowser:
|
||||||
|
|
||||||
due = node.review_count + node.learn_count
|
due = node.review_count + node.learn_count
|
||||||
|
|
||||||
def indent():
|
def indent() -> str:
|
||||||
return " " * 6 * (node.level - 1)
|
return " " * 6 * (node.level - 1)
|
||||||
|
|
||||||
if node.deck_id == ctx.current_deck_id:
|
if node.deck_id == ctx.current_deck_id:
|
||||||
|
@ -202,7 +202,7 @@ class DeckBrowser:
|
||||||
node.name,
|
node.name,
|
||||||
)
|
)
|
||||||
# due counts
|
# due counts
|
||||||
def nonzeroColour(cnt, klass):
|
def nonzeroColour(cnt: int, klass: str) -> str:
|
||||||
if not cnt:
|
if not cnt:
|
||||||
klass = "zero-count"
|
klass = "zero-count"
|
||||||
return f'<span class="{klass}">{cnt}</span>'
|
return f'<span class="{klass}">{cnt}</span>'
|
||||||
|
@ -222,7 +222,7 @@ class DeckBrowser:
|
||||||
buf += self._render_deck_node(child, ctx)
|
buf += self._render_deck_node(child, ctx)
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def _topLevelDragRow(self):
|
def _topLevelDragRow(self) -> str:
|
||||||
return "<tr class='top-level-drag-row'><td colspan='6'> </td></tr>"
|
return "<tr class='top-level-drag-row'><td colspan='6'> </td></tr>"
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
|
@ -260,7 +260,7 @@ class DeckBrowser:
|
||||||
return
|
return
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def _options(self, did):
|
def _options(self, did) -> None:
|
||||||
# select the deck first, because the dyn deck conf assumes the deck
|
# select the deck first, because the dyn deck conf assumes the deck
|
||||||
# we're editing is the current one
|
# we're editing is the current one
|
||||||
self.mw.col.decks.select(did)
|
self.mw.col.decks.select(did)
|
||||||
|
@ -297,10 +297,10 @@ class DeckBrowser:
|
||||||
def _delete(self, did: int) -> None:
|
def _delete(self, did: int) -> None:
|
||||||
if self.ask_delete_deck(did):
|
if self.ask_delete_deck(did):
|
||||||
|
|
||||||
def do_delete():
|
def do_delete() -> None:
|
||||||
return self.mw.col.decks.rem(did, True)
|
return self.mw.col.decks.rem(did, True)
|
||||||
|
|
||||||
def on_done(fut: Future):
|
def on_done(fut: Future) -> None:
|
||||||
self.show()
|
self.show()
|
||||||
res = fut.result() # Required to check for errors
|
res = fut.result() # Required to check for errors
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ class DeckBrowser:
|
||||||
["Ctrl+Shift+I", "import", tr(TR.DECKS_IMPORT_FILE)],
|
["Ctrl+Shift+I", "import", tr(TR.DECKS_IMPORT_FILE)],
|
||||||
]
|
]
|
||||||
|
|
||||||
def _drawButtons(self):
|
def _drawButtons(self) -> None:
|
||||||
buf = ""
|
buf = ""
|
||||||
drawLinks = deepcopy(self.drawLinks)
|
drawLinks = deepcopy(self.drawLinks)
|
||||||
for b in drawLinks:
|
for b in drawLinks:
|
||||||
|
@ -332,5 +332,5 @@ class DeckBrowser:
|
||||||
web_context=DeckBrowserBottomBar(self),
|
web_context=DeckBrowserBottomBar(self),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _onShared(self):
|
def _onShared(self) -> None:
|
||||||
openLink(aqt.appShared + "decks/")
|
openLink(aqt.appShared + "decks/")
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QLineEdit
|
from PyQt5.QtWidgets import QLineEdit
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.consts import NEW_CARDS_RANDOM
|
from anki.consts import NEW_CARDS_RANDOM
|
||||||
|
from anki.decks import DeckConfig
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -28,7 +29,7 @@ from aqt.utils import (
|
||||||
|
|
||||||
|
|
||||||
class DeckConf(QDialog):
|
class DeckConf(QDialog):
|
||||||
def __init__(self, mw: aqt.AnkiQt, deck: Dict):
|
def __init__(self, mw: aqt.AnkiQt, deck: Dict) -> None:
|
||||||
QDialog.__init__(self, mw)
|
QDialog.__init__(self, mw)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.deck = deck
|
self.deck = deck
|
||||||
|
@ -60,7 +61,7 @@ class DeckConf(QDialog):
|
||||||
self.exec_()
|
self.exec_()
|
||||||
saveGeom(self, "deckconf")
|
saveGeom(self, "deckconf")
|
||||||
|
|
||||||
def setupCombos(self):
|
def setupCombos(self) -> None:
|
||||||
import anki.consts as cs
|
import anki.consts as cs
|
||||||
|
|
||||||
f = self.form
|
f = self.form
|
||||||
|
@ -70,12 +71,12 @@ class DeckConf(QDialog):
|
||||||
# Conf list
|
# Conf list
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def setupConfs(self):
|
def setupConfs(self) -> None:
|
||||||
qconnect(self.form.dconf.currentIndexChanged, self.onConfChange)
|
qconnect(self.form.dconf.currentIndexChanged, self.onConfChange)
|
||||||
self.conf = None
|
self.conf: Optional[DeckConfig] = None
|
||||||
self.loadConfs()
|
self.loadConfs()
|
||||||
|
|
||||||
def loadConfs(self):
|
def loadConfs(self) -> None:
|
||||||
current = self.deck["conf"]
|
current = self.deck["conf"]
|
||||||
self.confList = self.mw.col.decks.allConf()
|
self.confList = self.mw.col.decks.allConf()
|
||||||
self.confList.sort(key=itemgetter("name"))
|
self.confList.sort(key=itemgetter("name"))
|
||||||
|
@ -92,7 +93,7 @@ class DeckConf(QDialog):
|
||||||
self._origNewOrder = self.confList[startOn]["new"]["order"]
|
self._origNewOrder = self.confList[startOn]["new"]["order"]
|
||||||
self.onConfChange(startOn)
|
self.onConfChange(startOn)
|
||||||
|
|
||||||
def confOpts(self):
|
def confOpts(self) -> None:
|
||||||
m = QMenu(self.mw)
|
m = QMenu(self.mw)
|
||||||
a = m.addAction(tr(TR.ACTIONS_ADD))
|
a = m.addAction(tr(TR.ACTIONS_ADD))
|
||||||
qconnect(a.triggered, self.addGroup)
|
qconnect(a.triggered, self.addGroup)
|
||||||
|
@ -106,7 +107,7 @@ class DeckConf(QDialog):
|
||||||
a.setEnabled(False)
|
a.setEnabled(False)
|
||||||
m.exec_(QCursor.pos())
|
m.exec_(QCursor.pos())
|
||||||
|
|
||||||
def onConfChange(self, idx):
|
def onConfChange(self, idx) -> None:
|
||||||
if self.ignoreConfChange:
|
if self.ignoreConfChange:
|
||||||
return
|
return
|
||||||
if self.conf:
|
if self.conf:
|
||||||
|
@ -159,7 +160,7 @@ class DeckConf(QDialog):
|
||||||
self.saveConf()
|
self.saveConf()
|
||||||
self.loadConfs()
|
self.loadConfs()
|
||||||
|
|
||||||
def setChildren(self):
|
def setChildren(self) -> None:
|
||||||
if not askUser(tr(TR.SCHEDULING_SET_ALL_DECKS_BELOW_TO, val=self.deck["name"])):
|
if not askUser(tr(TR.SCHEDULING_SET_ALL_DECKS_BELOW_TO, val=self.deck["name"])):
|
||||||
return
|
return
|
||||||
for did in self.childDids:
|
for did in self.childDids:
|
||||||
|
@ -173,8 +174,8 @@ class DeckConf(QDialog):
|
||||||
# Loading
|
# Loading
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def listToUser(self, l):
|
def listToUser(self, l) -> str:
|
||||||
def num_to_user(n: Union[int, float]):
|
def num_to_user(n: Union[int, float]) -> str:
|
||||||
if n == round(n):
|
if n == round(n):
|
||||||
return str(int(n))
|
return str(int(n))
|
||||||
else:
|
else:
|
||||||
|
@ -182,7 +183,7 @@ class DeckConf(QDialog):
|
||||||
|
|
||||||
return " ".join(map(num_to_user, l))
|
return " ".join(map(num_to_user, l))
|
||||||
|
|
||||||
def parentLimText(self, type="new"):
|
def parentLimText(self, type="new") -> str:
|
||||||
# top level?
|
# top level?
|
||||||
if "::" not in self.deck["name"]:
|
if "::" not in self.deck["name"]:
|
||||||
return ""
|
return ""
|
||||||
|
@ -196,7 +197,7 @@ class DeckConf(QDialog):
|
||||||
lim = min(x, lim)
|
lim = min(x, lim)
|
||||||
return tr(TR.SCHEDULING_PARENT_LIMIT, val=lim)
|
return tr(TR.SCHEDULING_PARENT_LIMIT, val=lim)
|
||||||
|
|
||||||
def loadConf(self):
|
def loadConf(self) -> None:
|
||||||
self.conf = self.mw.col.decks.confForDid(self.deck["id"])
|
self.conf = self.mw.col.decks.confForDid(self.deck["id"])
|
||||||
# new
|
# new
|
||||||
c = self.conf["new"]
|
c = self.conf["new"]
|
||||||
|
@ -238,7 +239,7 @@ class DeckConf(QDialog):
|
||||||
f.desc.setPlainText(self.deck["desc"])
|
f.desc.setPlainText(self.deck["desc"])
|
||||||
gui_hooks.deck_conf_did_load_config(self, self.deck, self.conf)
|
gui_hooks.deck_conf_did_load_config(self, self.deck, self.conf)
|
||||||
|
|
||||||
def onRestore(self):
|
def onRestore(self) -> None:
|
||||||
self.mw.progress.start()
|
self.mw.progress.start()
|
||||||
self.mw.col.decks.restoreToDefault(self.conf)
|
self.mw.col.decks.restoreToDefault(self.conf)
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
|
@ -247,7 +248,7 @@ class DeckConf(QDialog):
|
||||||
# New order
|
# New order
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def onNewOrderChanged(self, new):
|
def onNewOrderChanged(self, new) -> None:
|
||||||
old = self.conf["new"]["order"]
|
old = self.conf["new"]["order"]
|
||||||
if old == new:
|
if old == new:
|
||||||
return
|
return
|
||||||
|
@ -280,7 +281,7 @@ class DeckConf(QDialog):
|
||||||
return
|
return
|
||||||
conf[key] = ret
|
conf[key] = ret
|
||||||
|
|
||||||
def saveConf(self):
|
def saveConf(self) -> None:
|
||||||
# new
|
# new
|
||||||
c = self.conf["new"]
|
c = self.conf["new"]
|
||||||
f = self.form
|
f = self.form
|
||||||
|
@ -324,10 +325,10 @@ class DeckConf(QDialog):
|
||||||
self.mw.col.decks.save(self.deck)
|
self.mw.col.decks.save(self.deck)
|
||||||
self.mw.col.decks.save(self.conf)
|
self.mw.col.decks.save(self.conf)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
self.saveConf()
|
self.saveConf()
|
||||||
self.mw.reset()
|
self.mw.reset()
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
|
@ -145,7 +145,7 @@ class DeckConf(QDialog):
|
||||||
|
|
||||||
self.mw.col.decks.save(d)
|
self.mw.col.decks.save(d)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.ok = False
|
self.ok = False
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ class DeckConf(QDialog):
|
||||||
# Step load/save - fixme: share with std options screen
|
# Step load/save - fixme: share with std options screen
|
||||||
########################################################
|
########################################################
|
||||||
|
|
||||||
def listToUser(self, l):
|
def listToUser(self, l) -> str:
|
||||||
return " ".join([str(x) for x in l])
|
return " ".join([str(x) for x in l])
|
||||||
|
|
||||||
def userToList(self, w, minSize=1) -> Optional[List[Union[float, int]]]:
|
def userToList(self, w, minSize=1) -> Optional[List[Union[float, int]]]:
|
||||||
|
|
|
@ -48,7 +48,7 @@ class EditCurrent(QDialog):
|
||||||
return
|
return
|
||||||
self.editor.setNote(n)
|
self.editor.setNote(n)
|
||||||
|
|
||||||
def reopen(self, mw):
|
def reopen(self, mw) -> None:
|
||||||
tooltip("Please finish editing the existing card first.")
|
tooltip("Please finish editing the existing card first.")
|
||||||
self.onReset()
|
self.onReset()
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@ class EditCurrent(QDialog):
|
||||||
aqt.dialogs.markClosed("EditCurrent")
|
aqt.dialogs.markClosed("EditCurrent")
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def closeWithCallback(self, onsuccess):
|
def closeWithCallback(self, onsuccess) -> None:
|
||||||
def callback():
|
def callback() -> None:
|
||||||
self._saveAndClose()
|
self._saveAndClose()
|
||||||
onsuccess()
|
onsuccess()
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ from aqt.utils import TR, disable_help_button, restoreGeom, saveGeom, tooltip, t
|
||||||
def show_empty_cards(mw: aqt.main.AnkiQt) -> None:
|
def show_empty_cards(mw: aqt.main.AnkiQt) -> None:
|
||||||
mw.progress.start()
|
mw.progress.start()
|
||||||
|
|
||||||
def on_done(fut):
|
def on_done(fut) -> None:
|
||||||
mw.progress.finish()
|
mw.progress.finish()
|
||||||
report: EmptyCardsReport = fut.result()
|
report: EmptyCardsReport = fut.result()
|
||||||
if not report.notes:
|
if not report.notes:
|
||||||
|
@ -54,7 +54,7 @@ class EmptyCardsDialog(QDialog):
|
||||||
style = "<style>.allempty { color: red; }</style>"
|
style = "<style>.allempty { color: red; }</style>"
|
||||||
self.form.webview.stdHtml(style + html, context=self)
|
self.form.webview.stdHtml(style + html, context=self)
|
||||||
|
|
||||||
def on_finished(code):
|
def on_finished(code) -> None:
|
||||||
saveGeom(self, "emptycards")
|
saveGeom(self, "emptycards")
|
||||||
|
|
||||||
qconnect(self.finished, on_finished)
|
qconnect(self.finished, on_finished)
|
||||||
|
@ -65,16 +65,16 @@ class EmptyCardsDialog(QDialog):
|
||||||
self._delete_button.setAutoDefault(False)
|
self._delete_button.setAutoDefault(False)
|
||||||
self._delete_button.clicked.connect(self._on_delete)
|
self._delete_button.clicked.connect(self._on_delete)
|
||||||
|
|
||||||
def _on_note_link_clicked(self, link):
|
def _on_note_link_clicked(self, link) -> None:
|
||||||
self.mw.browser_search(link)
|
self.mw.browser_search(link)
|
||||||
|
|
||||||
def _on_delete(self) -> None:
|
def _on_delete(self) -> None:
|
||||||
self.mw.progress.start()
|
self.mw.progress.start()
|
||||||
|
|
||||||
def delete():
|
def delete() -> int:
|
||||||
return self._delete_cards(self.form.keep_notes.isChecked())
|
return self._delete_cards(self.form.keep_notes.isChecked())
|
||||||
|
|
||||||
def on_done(fut):
|
def on_done(fut) -> None:
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
try:
|
try:
|
||||||
count = fut.result()
|
count = fut.result()
|
||||||
|
|
|
@ -16,7 +16,7 @@ from aqt.utils import TR, showText, showWarning, supportText, tr
|
||||||
|
|
||||||
if not os.environ.get("DEBUG"):
|
if not os.environ.get("DEBUG"):
|
||||||
|
|
||||||
def excepthook(etype, val, tb):
|
def excepthook(etype, val, tb) -> None:
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
"Caught exception:\n%s\n"
|
"Caught exception:\n%s\n"
|
||||||
% ("".join(traceback.format_exception(etype, val, tb)))
|
% ("".join(traceback.format_exception(etype, val, tb)))
|
||||||
|
@ -65,7 +65,7 @@ class ErrorHandler(QObject):
|
||||||
self.timer.setSingleShot(True)
|
self.timer.setSingleShot(True)
|
||||||
self.timer.start()
|
self.timer.start()
|
||||||
|
|
||||||
def tempFolderMsg(self):
|
def tempFolderMsg(self) -> str:
|
||||||
return tr(TR.QT_MISC_UNABLE_TO_ACCESS_ANKI_MEDIA_FOLDER)
|
return tr(TR.QT_MISC_UNABLE_TO_ACCESS_ANKI_MEDIA_FOLDER)
|
||||||
|
|
||||||
def onTimeout(self) -> None:
|
def onTimeout(self) -> None:
|
||||||
|
@ -105,7 +105,7 @@ class ErrorHandler(QObject):
|
||||||
txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
|
txt = txt + "<div style='white-space: pre-wrap'>" + error + "</div>"
|
||||||
showText(txt, type="html", copyBtn=True)
|
showText(txt, type="html", copyBtn=True)
|
||||||
|
|
||||||
def _addonText(self, error):
|
def _addonText(self, error: str) -> str:
|
||||||
matches = re.findall(r"addons21/(.*?)/", error)
|
matches = re.findall(r"addons21/(.*?)/", error)
|
||||||
if not matches:
|
if not matches:
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -42,7 +42,7 @@ class ExportDialog(QDialog):
|
||||||
self.setup(did)
|
self.setup(did)
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
def setup(self, did: Optional[int]):
|
def setup(self, did: Optional[int]) -> None:
|
||||||
self.exporters = exporters(self.col)
|
self.exporters = exporters(self.col)
|
||||||
# if a deck specified, start with .apkg type selected
|
# if a deck specified, start with .apkg type selected
|
||||||
idx = 0
|
idx = 0
|
||||||
|
@ -155,17 +155,17 @@ class ExportDialog(QDialog):
|
||||||
os.unlink(file)
|
os.unlink(file)
|
||||||
|
|
||||||
# progress handler
|
# progress handler
|
||||||
def exported_media(cnt):
|
def exported_media(cnt) -> None:
|
||||||
self.mw.taskman.run_on_main(
|
self.mw.taskman.run_on_main(
|
||||||
lambda: self.mw.progress.update(
|
lambda: self.mw.progress.update(
|
||||||
label=tr(TR.EXPORTING_EXPORTED_MEDIA_FILE, count=cnt)
|
label=tr(TR.EXPORTING_EXPORTED_MEDIA_FILE, count=cnt)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def do_export():
|
def do_export() -> None:
|
||||||
self.exporter.exportInto(file)
|
self.exporter.exportInto(file)
|
||||||
|
|
||||||
def on_done(future: Future):
|
def on_done(future: Future) -> None:
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
hooks.media_files_did_export.remove(exported_media)
|
hooks.media_files_did_export.remove(exported_media)
|
||||||
# raises if exporter failed
|
# raises if exporter failed
|
||||||
|
|
|
@ -23,7 +23,7 @@ from aqt.utils import (
|
||||||
|
|
||||||
|
|
||||||
class FieldDialog(QDialog):
|
class FieldDialog(QDialog):
|
||||||
def __init__(self, mw: AnkiQt, nt: NoteType, parent=None):
|
def __init__(self, mw: AnkiQt, nt: NoteType, parent=None) -> None:
|
||||||
QDialog.__init__(self, parent or mw)
|
QDialog.__init__(self, parent or mw)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.col = self.mw.col
|
self.col = self.mw.col
|
||||||
|
@ -68,7 +68,7 @@ class FieldDialog(QDialog):
|
||||||
qconnect(f.sortField.clicked, self.onSortField)
|
qconnect(f.sortField.clicked, self.onSortField)
|
||||||
qconnect(f.buttonBox.helpRequested, self.onHelp)
|
qconnect(f.buttonBox.helpRequested, self.onHelp)
|
||||||
|
|
||||||
def onDrop(self, ev):
|
def onDrop(self, ev) -> None:
|
||||||
fieldList = self.form.fieldList
|
fieldList = self.form.fieldList
|
||||||
indicatorPos = fieldList.dropIndicatorPosition()
|
indicatorPos = fieldList.dropIndicatorPosition()
|
||||||
dropPos = fieldList.indexAt(ev.pos()).row()
|
dropPos = fieldList.indexAt(ev.pos()).row()
|
||||||
|
@ -113,7 +113,7 @@ class FieldDialog(QDialog):
|
||||||
return None
|
return None
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
def onRename(self):
|
def onRename(self) -> None:
|
||||||
idx = self.currentIdx
|
idx = self.currentIdx
|
||||||
f = self.model["flds"][idx]
|
f = self.model["flds"][idx]
|
||||||
name = self._uniqueName(tr(TR.ACTIONS_NEW_NAME), self.currentIdx, f["name"])
|
name = self._uniqueName(tr(TR.ACTIONS_NEW_NAME), self.currentIdx, f["name"])
|
||||||
|
@ -141,9 +141,10 @@ class FieldDialog(QDialog):
|
||||||
self.fillFields()
|
self.fillFields()
|
||||||
self.form.fieldList.setCurrentRow(len(self.model["flds"]) - 1)
|
self.form.fieldList.setCurrentRow(len(self.model["flds"]) - 1)
|
||||||
|
|
||||||
def onDelete(self):
|
def onDelete(self) -> None:
|
||||||
if len(self.model["flds"]) < 2:
|
if len(self.model["flds"]) < 2:
|
||||||
return showWarning(tr(TR.FIELDS_NOTES_REQUIRE_AT_LEAST_ONE_FIELD))
|
showWarning(tr(TR.FIELDS_NOTES_REQUIRE_AT_LEAST_ONE_FIELD))
|
||||||
|
return
|
||||||
count = self.mm.useCount(self.model)
|
count = self.mm.useCount(self.model)
|
||||||
c = tr(TR.BROWSING_NOTE_COUNT, count=count)
|
c = tr(TR.BROWSING_NOTE_COUNT, count=count)
|
||||||
if not askUser(tr(TR.FIELDS_DELETE_FIELD_FROM, val=c)):
|
if not askUser(tr(TR.FIELDS_DELETE_FIELD_FROM, val=c)):
|
||||||
|
@ -157,7 +158,7 @@ class FieldDialog(QDialog):
|
||||||
self.fillFields()
|
self.fillFields()
|
||||||
self.form.fieldList.setCurrentRow(0)
|
self.form.fieldList.setCurrentRow(0)
|
||||||
|
|
||||||
def onPosition(self, delta=-1):
|
def onPosition(self, delta=-1) -> None:
|
||||||
idx = self.currentIdx
|
idx = self.currentIdx
|
||||||
l = len(self.model["flds"])
|
l = len(self.model["flds"])
|
||||||
txt = getOnlyText(tr(TR.FIELDS_NEW_POSITION_1, val=l), default=str(idx + 1))
|
txt = getOnlyText(tr(TR.FIELDS_NEW_POSITION_1, val=l), default=str(idx + 1))
|
||||||
|
@ -171,16 +172,16 @@ class FieldDialog(QDialog):
|
||||||
return
|
return
|
||||||
self.moveField(pos)
|
self.moveField(pos)
|
||||||
|
|
||||||
def onSortField(self):
|
def onSortField(self) -> None:
|
||||||
if not self.change_tracker.mark_schema():
|
if not self.change_tracker.mark_schema():
|
||||||
return False
|
return
|
||||||
# don't allow user to disable; it makes no sense
|
# don't allow user to disable; it makes no sense
|
||||||
self.form.sortField.setChecked(True)
|
self.form.sortField.setChecked(True)
|
||||||
self.mm.set_sort_index(self.model, self.form.fieldList.currentRow())
|
self.mm.set_sort_index(self.model, self.form.fieldList.currentRow())
|
||||||
|
|
||||||
def moveField(self, pos):
|
def moveField(self, pos) -> None:
|
||||||
if not self.change_tracker.mark_schema():
|
if not self.change_tracker.mark_schema():
|
||||||
return False
|
return
|
||||||
self.saveField()
|
self.saveField()
|
||||||
f = self.model["flds"][self.currentIdx]
|
f = self.model["flds"][self.currentIdx]
|
||||||
self.mm.reposition_field(self.model, f, pos - 1)
|
self.mm.reposition_field(self.model, f, pos - 1)
|
||||||
|
@ -231,10 +232,10 @@ class FieldDialog(QDialog):
|
||||||
def accept(self) -> None:
|
def accept(self) -> None:
|
||||||
self.saveField()
|
self.saveField()
|
||||||
|
|
||||||
def save():
|
def save() -> None:
|
||||||
self.mm.save(self.model)
|
self.mm.save(self.model)
|
||||||
|
|
||||||
def on_done(fut):
|
def on_done(fut) -> None:
|
||||||
try:
|
try:
|
||||||
fut.result()
|
fut.result()
|
||||||
except TemplateError as e:
|
except TemplateError as e:
|
||||||
|
@ -247,5 +248,5 @@ class FieldDialog(QDialog):
|
||||||
|
|
||||||
self.mw.taskman.with_progress(save, on_done, self)
|
self.mw.taskman.with_progress(save, on_done, self)
|
||||||
|
|
||||||
def onHelp(self):
|
def onHelp(self) -> None:
|
||||||
openHelp(HelpPage.CUSTOMIZING_FIELDS)
|
openHelp(HelpPage.CUSTOMIZING_FIELDS)
|
||||||
|
|
|
@ -35,7 +35,7 @@ from aqt.utils import (
|
||||||
|
|
||||||
|
|
||||||
class ChangeMap(QDialog):
|
class ChangeMap(QDialog):
|
||||||
def __init__(self, mw: AnkiQt, model, current):
|
def __init__(self, mw: AnkiQt, model, current) -> None:
|
||||||
QDialog.__init__(self, mw, Qt.Window)
|
QDialog.__init__(self, mw, Qt.Window)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.model = model
|
self.model = model
|
||||||
|
@ -60,11 +60,11 @@ class ChangeMap(QDialog):
|
||||||
self.frm.fields.setCurrentRow(n + 1)
|
self.frm.fields.setCurrentRow(n + 1)
|
||||||
self.field: Optional[str] = None
|
self.field: Optional[str] = None
|
||||||
|
|
||||||
def getField(self):
|
def getField(self) -> str:
|
||||||
self.exec_()
|
self.exec_()
|
||||||
return self.field
|
return self.field
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
row = self.frm.fields.currentRow()
|
row = self.frm.fields.currentRow()
|
||||||
if row < len(self.model["flds"]):
|
if row < len(self.model["flds"]):
|
||||||
self.field = self.model["flds"][row]["name"]
|
self.field = self.model["flds"][row]["name"]
|
||||||
|
@ -74,7 +74,7 @@ class ChangeMap(QDialog):
|
||||||
self.field = None
|
self.field = None
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ class ImportDialog(QDialog):
|
||||||
self.importer.initMapping()
|
self.importer.initMapping()
|
||||||
self.showMapping()
|
self.showMapping()
|
||||||
|
|
||||||
def onDelimiter(self):
|
def onDelimiter(self) -> None:
|
||||||
str = (
|
str = (
|
||||||
getOnlyText(
|
getOnlyText(
|
||||||
tr(TR.IMPORTING_BY_DEFAULT_ANKI_WILL_DETECT_THE),
|
tr(TR.IMPORTING_BY_DEFAULT_ANKI_WILL_DETECT_THE),
|
||||||
|
@ -136,7 +136,7 @@ class ImportDialog(QDialog):
|
||||||
return
|
return
|
||||||
self.hideMapping()
|
self.hideMapping()
|
||||||
|
|
||||||
def updateDelim():
|
def updateDelim() -> None:
|
||||||
self.importer.delimiter = str
|
self.importer.delimiter = str
|
||||||
self.importer.updateDelimiter()
|
self.importer.updateDelimiter()
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ class ImportDialog(QDialog):
|
||||||
self.mw.progress.start()
|
self.mw.progress.start()
|
||||||
self.mw.checkpoint(tr(TR.ACTIONS_IMPORT))
|
self.mw.checkpoint(tr(TR.ACTIONS_IMPORT))
|
||||||
|
|
||||||
def on_done(future: Future):
|
def on_done(future: Future) -> None:
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -221,7 +221,7 @@ class ImportDialog(QDialog):
|
||||||
self.mapbox.setContentsMargins(0, 0, 0, 0)
|
self.mapbox.setContentsMargins(0, 0, 0, 0)
|
||||||
self.mapwidget: Optional[QWidget] = None
|
self.mapwidget: Optional[QWidget] = None
|
||||||
|
|
||||||
def hideMapping(self):
|
def hideMapping(self) -> None:
|
||||||
self.frm.mappingGroup.hide()
|
self.frm.mappingGroup.hide()
|
||||||
|
|
||||||
def showMapping(
|
def showMapping(
|
||||||
|
@ -258,7 +258,7 @@ class ImportDialog(QDialog):
|
||||||
self.grid.addWidget(button, num, 2)
|
self.grid.addWidget(button, num, 2)
|
||||||
qconnect(button.clicked, lambda _, s=self, n=num: s.changeMappingNum(n))
|
qconnect(button.clicked, lambda _, s=self, n=num: s.changeMappingNum(n))
|
||||||
|
|
||||||
def changeMappingNum(self, n):
|
def changeMappingNum(self, n) -> None:
|
||||||
f = ChangeMap(self.mw, self.importer.model, self.mapping[n]).getField()
|
f = ChangeMap(self.mw, self.importer.model, self.mapping[n]).getField()
|
||||||
try:
|
try:
|
||||||
# make sure we don't have it twice
|
# make sure we don't have it twice
|
||||||
|
@ -270,7 +270,7 @@ class ImportDialog(QDialog):
|
||||||
if getattr(self.importer, "delimiter", False):
|
if getattr(self.importer, "delimiter", False):
|
||||||
self.savedDelimiter = self.importer.delimiter
|
self.savedDelimiter = self.importer.delimiter
|
||||||
|
|
||||||
def updateDelim():
|
def updateDelim() -> None:
|
||||||
self.importer.delimiter = self.savedDelimiter
|
self.importer.delimiter = self.savedDelimiter
|
||||||
|
|
||||||
self.showMapping(hook=updateDelim, keepMapping=True)
|
self.showMapping(hook=updateDelim, keepMapping=True)
|
||||||
|
@ -283,17 +283,17 @@ class ImportDialog(QDialog):
|
||||||
gui_hooks.current_note_type_did_change.remove(self.modelChanged)
|
gui_hooks.current_note_type_did_change.remove(self.modelChanged)
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def helpRequested(self):
|
def helpRequested(self) -> None:
|
||||||
openHelp(HelpPage.IMPORTING)
|
openHelp(HelpPage.IMPORTING)
|
||||||
|
|
||||||
def importModeChanged(self, newImportMode):
|
def importModeChanged(self, newImportMode) -> None:
|
||||||
if newImportMode == 0:
|
if newImportMode == 0:
|
||||||
self.frm.tagModified.setEnabled(True)
|
self.frm.tagModified.setEnabled(True)
|
||||||
else:
|
else:
|
||||||
self.frm.tagModified.setEnabled(False)
|
self.frm.tagModified.setEnabled(False)
|
||||||
|
|
||||||
|
|
||||||
def showUnicodeWarning():
|
def showUnicodeWarning() -> None:
|
||||||
"""Shorthand to show a standard warning."""
|
"""Shorthand to show a standard warning."""
|
||||||
showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8))
|
showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8))
|
||||||
|
|
||||||
|
@ -374,7 +374,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
|
||||||
# importing non-colpkg files
|
# importing non-colpkg files
|
||||||
mw.progress.start(immediate=True)
|
mw.progress.start(immediate=True)
|
||||||
|
|
||||||
def on_done(future: Future):
|
def on_done(future: Future) -> None:
|
||||||
mw.progress.finish()
|
mw.progress.finish()
|
||||||
try:
|
try:
|
||||||
future.result()
|
future.result()
|
||||||
|
@ -405,7 +405,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
|
||||||
mw.taskman.run_in_background(importer.run, on_done)
|
mw.taskman.run_in_background(importer.run, on_done)
|
||||||
|
|
||||||
|
|
||||||
def invalidZipMsg():
|
def invalidZipMsg() -> str:
|
||||||
return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO)
|
return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO)
|
||||||
|
|
||||||
|
|
||||||
|
@ -430,14 +430,14 @@ def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def replaceWithApkg(mw, file, backup):
|
def replaceWithApkg(mw, file, backup) -> None:
|
||||||
mw.unloadCollection(lambda: _replaceWithApkg(mw, file, backup))
|
mw.unloadCollection(lambda: _replaceWithApkg(mw, file, backup))
|
||||||
|
|
||||||
|
|
||||||
def _replaceWithApkg(mw, filename, backup):
|
def _replaceWithApkg(mw, filename, backup) -> None:
|
||||||
mw.progress.start(immediate=True)
|
mw.progress.start(immediate=True)
|
||||||
|
|
||||||
def do_import():
|
def do_import() -> None:
|
||||||
z = zipfile.ZipFile(filename)
|
z = zipfile.ZipFile(filename)
|
||||||
|
|
||||||
# v2 scheduler?
|
# v2 scheduler?
|
||||||
|
@ -472,7 +472,7 @@ def _replaceWithApkg(mw, filename, backup):
|
||||||
|
|
||||||
z.close()
|
z.close()
|
||||||
|
|
||||||
def on_done(future: Future):
|
def on_done(future: Future) -> None:
|
||||||
mw.progress.finish()
|
mw.progress.finish()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Legacy support
|
Legacy support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import List
|
from typing import Any, List
|
||||||
|
|
||||||
import anki
|
import anki
|
||||||
import aqt
|
import aqt
|
||||||
|
@ -31,7 +31,14 @@ def stripSounds(text) -> str:
|
||||||
return aqt.mw.col.media.strip_av_tags(text)
|
return aqt.mw.col.media.strip_av_tags(text)
|
||||||
|
|
||||||
|
|
||||||
def fmtTimeSpan(time, pad=0, point=0, short=False, inTime=False, unit=99):
|
def fmtTimeSpan(
|
||||||
|
time: Any,
|
||||||
|
pad: Any = 0,
|
||||||
|
point: Any = 0,
|
||||||
|
short: Any = False,
|
||||||
|
inTime: Any = False,
|
||||||
|
unit: Any = 99,
|
||||||
|
) -> Any:
|
||||||
print("fmtTimeSpan() has become col.format_timespan()")
|
print("fmtTimeSpan() has become col.format_timespan()")
|
||||||
return aqt.mw.col.format_timespan(time)
|
return aqt.mw.col.format_timespan(time)
|
||||||
|
|
||||||
|
|
102
qt/aqt/main.py
102
qt/aqt/main.py
|
@ -87,7 +87,7 @@ class ResetReason(enum.Enum):
|
||||||
|
|
||||||
|
|
||||||
class ResetRequired:
|
class ResetRequired:
|
||||||
def __init__(self, mw: AnkiQt):
|
def __init__(self, mw: AnkiQt) -> None:
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ class AnkiQt(QMainWindow):
|
||||||
else:
|
else:
|
||||||
fn = self.setupProfile
|
fn = self.setupProfile
|
||||||
|
|
||||||
def on_window_init():
|
def on_window_init() -> None:
|
||||||
fn()
|
fn()
|
||||||
gui_hooks.main_window_did_init()
|
gui_hooks.main_window_did_init()
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ class AnkiQt(QMainWindow):
|
||||||
"Actions that are deferred until after add-on loading."
|
"Actions that are deferred until after add-on loading."
|
||||||
self.toolbar.draw()
|
self.toolbar.draw()
|
||||||
|
|
||||||
def setupProfileAfterWebviewsLoaded(self):
|
def setupProfileAfterWebviewsLoaded(self) -> None:
|
||||||
for w in (self.web, self.bottomWeb):
|
for w in (self.web, self.bottomWeb):
|
||||||
if not w._domDone:
|
if not w._domDone:
|
||||||
self.progress.timer(
|
self.progress.timer(
|
||||||
|
@ -206,7 +206,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.onClose.emit() # type: ignore
|
self.onClose.emit() # type: ignore
|
||||||
evt.accept()
|
evt.accept()
|
||||||
|
|
||||||
def closeWithoutQuitting(self):
|
def closeWithoutQuitting(self) -> None:
|
||||||
self.closeFires = False
|
self.closeFires = False
|
||||||
self.close()
|
self.close()
|
||||||
self.closeFires = True
|
self.closeFires = True
|
||||||
|
@ -275,9 +275,10 @@ class AnkiQt(QMainWindow):
|
||||||
name = self.pm.profiles()[n]
|
name = self.pm.profiles()[n]
|
||||||
self.pm.load(name)
|
self.pm.load(name)
|
||||||
|
|
||||||
def openProfile(self):
|
def openProfile(self) -> None:
|
||||||
name = self.pm.profiles()[self.profileForm.profiles.currentRow()]
|
name = self.pm.profiles()[self.profileForm.profiles.currentRow()]
|
||||||
return self.pm.load(name)
|
self.pm.load(name)
|
||||||
|
return
|
||||||
|
|
||||||
def onOpenProfile(self) -> None:
|
def onOpenProfile(self) -> None:
|
||||||
self.profileDiag.hide()
|
self.profileDiag.hide()
|
||||||
|
@ -288,34 +289,37 @@ class AnkiQt(QMainWindow):
|
||||||
def profileNameOk(self, name: str) -> bool:
|
def profileNameOk(self, name: str) -> bool:
|
||||||
return not checkInvalidFilename(name) and name != "addons21"
|
return not checkInvalidFilename(name) and name != "addons21"
|
||||||
|
|
||||||
def onAddProfile(self):
|
def onAddProfile(self) -> None:
|
||||||
name = getOnlyText(tr(TR.ACTIONS_NAME)).strip()
|
name = getOnlyText(tr(TR.ACTIONS_NAME)).strip()
|
||||||
if name:
|
if name:
|
||||||
if name in self.pm.profiles():
|
if name in self.pm.profiles():
|
||||||
return showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
||||||
|
return
|
||||||
if not self.profileNameOk(name):
|
if not self.profileNameOk(name):
|
||||||
return
|
return
|
||||||
self.pm.create(name)
|
self.pm.create(name)
|
||||||
self.pm.name = name
|
self.pm.name = name
|
||||||
self.refreshProfilesList()
|
self.refreshProfilesList()
|
||||||
|
|
||||||
def onRenameProfile(self):
|
def onRenameProfile(self) -> None:
|
||||||
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=self.pm.name).strip()
|
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=self.pm.name).strip()
|
||||||
if not name:
|
if not name:
|
||||||
return
|
return
|
||||||
if name == self.pm.name:
|
if name == self.pm.name:
|
||||||
return
|
return
|
||||||
if name in self.pm.profiles():
|
if name in self.pm.profiles():
|
||||||
return showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
showWarning(tr(TR.QT_MISC_NAME_EXISTS))
|
||||||
|
return
|
||||||
if not self.profileNameOk(name):
|
if not self.profileNameOk(name):
|
||||||
return
|
return
|
||||||
self.pm.rename(name)
|
self.pm.rename(name)
|
||||||
self.refreshProfilesList()
|
self.refreshProfilesList()
|
||||||
|
|
||||||
def onRemProfile(self):
|
def onRemProfile(self) -> None:
|
||||||
profs = self.pm.profiles()
|
profs = self.pm.profiles()
|
||||||
if len(profs) < 2:
|
if len(profs) < 2:
|
||||||
return showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE))
|
showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE))
|
||||||
|
return
|
||||||
# sure?
|
# sure?
|
||||||
if not askUser(
|
if not askUser(
|
||||||
tr(TR.QT_MISC_ALL_CARDS_NOTES_AND_MEDIA_FOR),
|
tr(TR.QT_MISC_ALL_CARDS_NOTES_AND_MEDIA_FOR),
|
||||||
|
@ -326,7 +330,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.pm.remove(self.pm.name)
|
self.pm.remove(self.pm.name)
|
||||||
self.refreshProfilesList()
|
self.refreshProfilesList()
|
||||||
|
|
||||||
def onOpenBackup(self):
|
def onOpenBackup(self) -> None:
|
||||||
if not askUser(
|
if not askUser(
|
||||||
tr(TR.QT_MISC_REPLACE_YOUR_COLLECTION_WITH_AN_EARLIER),
|
tr(TR.QT_MISC_REPLACE_YOUR_COLLECTION_WITH_AN_EARLIER),
|
||||||
msgfunc=QMessageBox.warning,
|
msgfunc=QMessageBox.warning,
|
||||||
|
@ -334,7 +338,7 @@ class AnkiQt(QMainWindow):
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
def doOpen(path):
|
def doOpen(path) -> None:
|
||||||
self._openBackup(path)
|
self._openBackup(path)
|
||||||
|
|
||||||
getFile(
|
getFile(
|
||||||
|
@ -345,7 +349,7 @@ class AnkiQt(QMainWindow):
|
||||||
dir=self.pm.backupFolder(),
|
dir=self.pm.backupFolder(),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _openBackup(self, path):
|
def _openBackup(self, path) -> None:
|
||||||
try:
|
try:
|
||||||
# move the existing collection to the trash, as it may not open
|
# move the existing collection to the trash, as it may not open
|
||||||
self.pm.trashCollection()
|
self.pm.trashCollection()
|
||||||
|
@ -360,14 +364,14 @@ class AnkiQt(QMainWindow):
|
||||||
|
|
||||||
self.onOpenProfile()
|
self.onOpenProfile()
|
||||||
|
|
||||||
def _on_downgrade(self):
|
def _on_downgrade(self) -> None:
|
||||||
self.progress.start()
|
self.progress.start()
|
||||||
profiles = self.pm.profiles()
|
profiles = self.pm.profiles()
|
||||||
|
|
||||||
def downgrade():
|
def downgrade() -> List[str]:
|
||||||
return self.pm.downgrade(profiles)
|
return self.pm.downgrade(profiles)
|
||||||
|
|
||||||
def on_done(future):
|
def on_done(future) -> None:
|
||||||
self.progress.finish()
|
self.progress.finish()
|
||||||
problems = future.result()
|
problems = future.result()
|
||||||
if not problems:
|
if not problems:
|
||||||
|
@ -409,7 +413,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.pendingImport = None
|
self.pendingImport = None
|
||||||
gui_hooks.profile_did_open()
|
gui_hooks.profile_did_open()
|
||||||
|
|
||||||
def _onsuccess():
|
def _onsuccess() -> None:
|
||||||
self._refresh_after_sync()
|
self._refresh_after_sync()
|
||||||
if onsuccess:
|
if onsuccess:
|
||||||
onsuccess()
|
onsuccess()
|
||||||
|
@ -417,7 +421,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.maybe_auto_sync_on_open_close(_onsuccess)
|
self.maybe_auto_sync_on_open_close(_onsuccess)
|
||||||
|
|
||||||
def unloadProfile(self, onsuccess: Callable) -> None:
|
def unloadProfile(self, onsuccess: Callable) -> None:
|
||||||
def callback():
|
def callback() -> None:
|
||||||
self._unloadProfile()
|
self._unloadProfile()
|
||||||
onsuccess()
|
onsuccess()
|
||||||
|
|
||||||
|
@ -447,7 +451,7 @@ class AnkiQt(QMainWindow):
|
||||||
def unloadProfileAndExit(self) -> None:
|
def unloadProfileAndExit(self) -> None:
|
||||||
self.unloadProfile(self.cleanupAndExit)
|
self.unloadProfile(self.cleanupAndExit)
|
||||||
|
|
||||||
def unloadProfileAndShowProfileManager(self):
|
def unloadProfileAndShowProfileManager(self) -> None:
|
||||||
self.unloadProfile(self.showProfileManager)
|
self.unloadProfile(self.showProfileManager)
|
||||||
|
|
||||||
def cleanupAndExit(self) -> None:
|
def cleanupAndExit(self) -> None:
|
||||||
|
@ -520,14 +524,14 @@ class AnkiQt(QMainWindow):
|
||||||
self.col.reopen()
|
self.col.reopen()
|
||||||
|
|
||||||
def unloadCollection(self, onsuccess: Callable) -> None:
|
def unloadCollection(self, onsuccess: Callable) -> None:
|
||||||
def after_media_sync():
|
def after_media_sync() -> None:
|
||||||
self._unloadCollection()
|
self._unloadCollection()
|
||||||
onsuccess()
|
onsuccess()
|
||||||
|
|
||||||
def after_sync():
|
def after_sync() -> None:
|
||||||
self.media_syncer.show_diag_until_finished(after_media_sync)
|
self.media_syncer.show_diag_until_finished(after_media_sync)
|
||||||
|
|
||||||
def before_sync():
|
def before_sync() -> None:
|
||||||
self.setEnabled(False)
|
self.setEnabled(False)
|
||||||
self.maybe_auto_sync_on_open_close(after_sync)
|
self.maybe_auto_sync_on_open_close(after_sync)
|
||||||
|
|
||||||
|
@ -565,7 +569,7 @@ class AnkiQt(QMainWindow):
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
class BackupThread(Thread):
|
class BackupThread(Thread):
|
||||||
def __init__(self, path, data):
|
def __init__(self, path, data) -> None:
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
self.path = path
|
self.path = path
|
||||||
self.data = data
|
self.data = data
|
||||||
|
@ -574,7 +578,7 @@ class AnkiQt(QMainWindow):
|
||||||
with open(self.path, "wb") as file:
|
with open(self.path, "wb") as file:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
z = zipfile.ZipFile(self.path, "w", zipfile.ZIP_DEFLATED)
|
z = zipfile.ZipFile(self.path, "w", zipfile.ZIP_DEFLATED)
|
||||||
z.writestr("collection.anki2", self.data)
|
z.writestr("collection.anki2", self.data)
|
||||||
z.writestr("media", "{}")
|
z.writestr("media", "{}")
|
||||||
|
@ -700,7 +704,7 @@ class AnkiQt(QMainWindow):
|
||||||
self.state = self.returnState
|
self.state = self.returnState
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def delayedMaybeReset(self):
|
def delayedMaybeReset(self) -> None:
|
||||||
# if we redraw the page in a button click event it will often crash on
|
# if we redraw the page in a button click event it will often crash on
|
||||||
# windows
|
# windows
|
||||||
self.progress.timer(100, self.maybeReset, False)
|
self.progress.timer(100, self.maybeReset, False)
|
||||||
|
@ -801,9 +805,9 @@ title="%s" %s>%s</button>""" % (
|
||||||
signal.signal(signal.SIGINT, self.onUnixSignal)
|
signal.signal(signal.SIGINT, self.onUnixSignal)
|
||||||
signal.signal(signal.SIGTERM, self.onUnixSignal)
|
signal.signal(signal.SIGTERM, self.onUnixSignal)
|
||||||
|
|
||||||
def onUnixSignal(self, signum, frame):
|
def onUnixSignal(self, signum, frame) -> None:
|
||||||
# schedule a rollback & quit
|
# schedule a rollback & quit
|
||||||
def quit():
|
def quit() -> None:
|
||||||
self.col.db.rollback()
|
self.col.db.rollback()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
@ -888,13 +892,13 @@ title="%s" %s>%s</button>""" % (
|
||||||
def _refresh_after_sync(self) -> None:
|
def _refresh_after_sync(self) -> None:
|
||||||
self.toolbar.redraw()
|
self.toolbar.redraw()
|
||||||
|
|
||||||
def _sync_collection_and_media(self, after_sync: Callable[[], None]):
|
def _sync_collection_and_media(self, after_sync: Callable[[], None]) -> None:
|
||||||
"Caller should ensure auth available."
|
"Caller should ensure auth available."
|
||||||
# start media sync if not already running
|
# start media sync if not already running
|
||||||
if not self.media_syncer.is_syncing():
|
if not self.media_syncer.is_syncing():
|
||||||
self.media_syncer.start()
|
self.media_syncer.start()
|
||||||
|
|
||||||
def on_collection_sync_finished():
|
def on_collection_sync_finished() -> None:
|
||||||
self.col.clearUndo()
|
self.col.clearUndo()
|
||||||
self.col.models._clear_cache()
|
self.col.models._clear_cache()
|
||||||
gui_hooks.sync_did_finish()
|
gui_hooks.sync_did_finish()
|
||||||
|
@ -927,7 +931,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
)
|
)
|
||||||
|
|
||||||
# legacy
|
# legacy
|
||||||
def _sync(self):
|
def _sync(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
onSync = on_sync_button_clicked
|
onSync = on_sync_button_clicked
|
||||||
|
@ -1057,7 +1061,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
def onEditCurrent(self) -> None:
|
def onEditCurrent(self) -> None:
|
||||||
aqt.dialogs.open("EditCurrent", self)
|
aqt.dialogs.open("EditCurrent", self)
|
||||||
|
|
||||||
def onDeckConf(self, deck=None):
|
def onDeckConf(self, deck=None) -> None:
|
||||||
if not deck:
|
if not deck:
|
||||||
deck = self.col.decks.current()
|
deck = self.col.decks.current()
|
||||||
if deck["dyn"]:
|
if deck["dyn"]:
|
||||||
|
@ -1069,7 +1073,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
|
|
||||||
aqt.deckconf.DeckConf(self, deck)
|
aqt.deckconf.DeckConf(self, deck)
|
||||||
|
|
||||||
def onOverview(self):
|
def onOverview(self) -> None:
|
||||||
self.col.reset()
|
self.col.reset()
|
||||||
self.moveToState("overview")
|
self.moveToState("overview")
|
||||||
|
|
||||||
|
@ -1083,7 +1087,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
else:
|
else:
|
||||||
aqt.dialogs.open("NewDeckStats", self)
|
aqt.dialogs.open("NewDeckStats", self)
|
||||||
|
|
||||||
def onPrefs(self):
|
def onPrefs(self) -> None:
|
||||||
aqt.dialogs.open("Preferences", self)
|
aqt.dialogs.open("Preferences", self)
|
||||||
|
|
||||||
def onNoteTypes(self) -> None:
|
def onNoteTypes(self) -> None:
|
||||||
|
@ -1091,13 +1095,13 @@ title="%s" %s>%s</button>""" % (
|
||||||
|
|
||||||
aqt.models.Models(self, self, fromMain=True)
|
aqt.models.Models(self, self, fromMain=True)
|
||||||
|
|
||||||
def onAbout(self):
|
def onAbout(self) -> None:
|
||||||
aqt.dialogs.open("About", self)
|
aqt.dialogs.open("About", self)
|
||||||
|
|
||||||
def onDonate(self):
|
def onDonate(self) -> None:
|
||||||
openLink(aqt.appDonate)
|
openLink(aqt.appDonate)
|
||||||
|
|
||||||
def onDocumentation(self):
|
def onDocumentation(self) -> None:
|
||||||
openHelp(HelpPage.INDEX)
|
openHelp(HelpPage.INDEX)
|
||||||
|
|
||||||
# Importing & exporting
|
# Importing & exporting
|
||||||
|
@ -1126,7 +1130,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
# Installing add-ons from CLI / mimetype handler
|
# Installing add-ons from CLI / mimetype handler
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def installAddon(self, path: str, startup: bool = False):
|
def installAddon(self, path: str, startup: bool = False) -> None:
|
||||||
from aqt.addons import installAddonPackages
|
from aqt.addons import installAddonPackages
|
||||||
|
|
||||||
installAddonPackages(
|
installAddonPackages(
|
||||||
|
@ -1201,14 +1205,14 @@ title="%s" %s>%s</button>""" % (
|
||||||
qconnect(self.autoUpdate.clockIsOff, self.clockIsOff)
|
qconnect(self.autoUpdate.clockIsOff, self.clockIsOff)
|
||||||
self.autoUpdate.start()
|
self.autoUpdate.start()
|
||||||
|
|
||||||
def newVerAvail(self, ver):
|
def newVerAvail(self, ver) -> None:
|
||||||
if self.pm.meta.get("suppressUpdate", None) != ver:
|
if self.pm.meta.get("suppressUpdate", None) != ver:
|
||||||
aqt.update.askAndUpdate(self, ver)
|
aqt.update.askAndUpdate(self, ver)
|
||||||
|
|
||||||
def newMsg(self, data):
|
def newMsg(self, data) -> None:
|
||||||
aqt.update.showMessages(self, data)
|
aqt.update.showMessages(self, data)
|
||||||
|
|
||||||
def clockIsOff(self, diff):
|
def clockIsOff(self, diff) -> None:
|
||||||
if devMode:
|
if devMode:
|
||||||
print("clock is off; ignoring")
|
print("clock is off; ignoring")
|
||||||
return
|
return
|
||||||
|
@ -1229,7 +1233,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
# SIGINT/SIGTERM is processed without a long delay
|
# SIGINT/SIGTERM is processed without a long delay
|
||||||
self.progress.timer(1000, lambda: None, True, False)
|
self.progress.timer(1000, lambda: None, True, False)
|
||||||
|
|
||||||
def onRefreshTimer(self):
|
def onRefreshTimer(self) -> None:
|
||||||
if self.state == "deckBrowser":
|
if self.state == "deckBrowser":
|
||||||
self.deckBrowser.refresh()
|
self.deckBrowser.refresh()
|
||||||
elif self.state == "overview":
|
elif self.state == "overview":
|
||||||
|
@ -1256,7 +1260,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
|
|
||||||
self._activeWindowOnPlay: Optional[QWidget] = None
|
self._activeWindowOnPlay: Optional[QWidget] = None
|
||||||
|
|
||||||
def onOdueInvalid(self):
|
def onOdueInvalid(self) -> None:
|
||||||
showWarning(tr(TR.QT_MISC_INVALID_PROPERTY_FOUND_ON_CARD_PLEASE))
|
showWarning(tr(TR.QT_MISC_INVALID_PROPERTY_FOUND_ON_CARD_PLEASE))
|
||||||
|
|
||||||
def _isVideo(self, tag: AVTag) -> bool:
|
def _isVideo(self, tag: AVTag) -> bool:
|
||||||
|
@ -1343,11 +1347,11 @@ title="%s" %s>%s</button>""" % (
|
||||||
# Debugging
|
# Debugging
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def onDebug(self):
|
def onDebug(self) -> None:
|
||||||
frm = self.debug_diag_form = aqt.forms.debug.Ui_Dialog()
|
frm = self.debug_diag_form = aqt.forms.debug.Ui_Dialog()
|
||||||
|
|
||||||
class DebugDialog(QDialog):
|
class DebugDialog(QDialog):
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
super().reject()
|
super().reject()
|
||||||
saveSplitter(frm.splitter, "DebugConsoleWindow")
|
saveSplitter(frm.splitter, "DebugConsoleWindow")
|
||||||
saveGeom(self, "DebugConsoleWindow")
|
saveGeom(self, "DebugConsoleWindow")
|
||||||
|
@ -1394,7 +1398,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
mw = self
|
mw = self
|
||||||
|
|
||||||
class Stream:
|
class Stream:
|
||||||
def write(self, data):
|
def write(self, data) -> None:
|
||||||
mw._output += data
|
mw._output += data
|
||||||
|
|
||||||
if on:
|
if on:
|
||||||
|
@ -1445,7 +1449,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
self._card_repr(card)
|
self._card_repr(card)
|
||||||
return card
|
return card
|
||||||
|
|
||||||
def onDebugPrint(self, frm):
|
def onDebugPrint(self, frm) -> None:
|
||||||
cursor = frm.text.textCursor()
|
cursor = frm.text.textCursor()
|
||||||
position = cursor.position()
|
position = cursor.position()
|
||||||
cursor.select(QTextCursor.LineUnderCursor)
|
cursor.select(QTextCursor.LineUnderCursor)
|
||||||
|
@ -1458,7 +1462,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
frm.text.setTextCursor(cursor)
|
frm.text.setTextCursor(cursor)
|
||||||
self.onDebugRet(frm)
|
self.onDebugRet(frm)
|
||||||
|
|
||||||
def onDebugRet(self, frm):
|
def onDebugRet(self, frm) -> None:
|
||||||
import pprint
|
import pprint
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ class MediaChecker:
|
||||||
diag.exec_()
|
diag.exec_()
|
||||||
saveGeom(diag, "checkmediadb")
|
saveGeom(diag, "checkmediadb")
|
||||||
|
|
||||||
def _on_render_latex(self):
|
def _on_render_latex(self) -> None:
|
||||||
self.progress_dialog = self.mw.progress.start()
|
self.progress_dialog = self.mw.progress.start()
|
||||||
try:
|
try:
|
||||||
out = self.mw.col.media.render_all_latex(self._on_render_latex_progress)
|
out = self.mw.col.media.render_all_latex(self._on_render_latex_progress)
|
||||||
|
@ -160,7 +160,7 @@ class MediaChecker:
|
||||||
self.mw.progress.update(tr(TR.MEDIA_CHECK_CHECKED, count=count))
|
self.mw.progress.update(tr(TR.MEDIA_CHECK_CHECKED, count=count))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _on_trash_files(self, fnames: Sequence[str]):
|
def _on_trash_files(self, fnames: Sequence[str]) -> None:
|
||||||
if not askUser(tr(TR.MEDIA_CHECK_DELETE_UNUSED_CONFIRM)):
|
if not askUser(tr(TR.MEDIA_CHECK_DELETE_UNUSED_CONFIRM)):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -183,14 +183,14 @@ class MediaChecker:
|
||||||
|
|
||||||
tooltip(tr(TR.MEDIA_CHECK_DELETE_UNUSED_COMPLETE, count=total))
|
tooltip(tr(TR.MEDIA_CHECK_DELETE_UNUSED_COMPLETE, count=total))
|
||||||
|
|
||||||
def _on_empty_trash(self):
|
def _on_empty_trash(self) -> None:
|
||||||
self.progress_dialog = self.mw.progress.start()
|
self.progress_dialog = self.mw.progress.start()
|
||||||
self._set_progress_enabled(True)
|
self._set_progress_enabled(True)
|
||||||
|
|
||||||
def empty_trash():
|
def empty_trash() -> None:
|
||||||
self.mw.col.media.empty_trash()
|
self.mw.col.media.empty_trash()
|
||||||
|
|
||||||
def on_done(fut: Future):
|
def on_done(fut: Future) -> None:
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
self._set_progress_enabled(False)
|
self._set_progress_enabled(False)
|
||||||
# check for errors
|
# check for errors
|
||||||
|
@ -200,14 +200,14 @@ class MediaChecker:
|
||||||
|
|
||||||
self.mw.taskman.run_in_background(empty_trash, on_done)
|
self.mw.taskman.run_in_background(empty_trash, on_done)
|
||||||
|
|
||||||
def _on_restore_trash(self):
|
def _on_restore_trash(self) -> None:
|
||||||
self.progress_dialog = self.mw.progress.start()
|
self.progress_dialog = self.mw.progress.start()
|
||||||
self._set_progress_enabled(True)
|
self._set_progress_enabled(True)
|
||||||
|
|
||||||
def restore_trash():
|
def restore_trash() -> None:
|
||||||
self.mw.col.media.restore_trash()
|
self.mw.col.media.restore_trash()
|
||||||
|
|
||||||
def on_done(fut: Future):
|
def on_done(fut: Future) -> None:
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
self._set_progress_enabled(False)
|
self._set_progress_enabled(False)
|
||||||
# check for errors
|
# check for errors
|
||||||
|
|
|
@ -12,6 +12,7 @@ import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import flask_cors # type: ignore
|
import flask_cors # type: ignore
|
||||||
|
@ -52,11 +53,11 @@ class MediaServer(threading.Thread):
|
||||||
_ready = threading.Event()
|
_ready = threading.Event()
|
||||||
daemon = True
|
daemon = True
|
||||||
|
|
||||||
def __init__(self, mw: aqt.main.AnkiQt, *args, **kwargs):
|
def __init__(self, mw: aqt.main.AnkiQt, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.is_shutdown = False
|
self.is_shutdown = False
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
try:
|
try:
|
||||||
if devMode:
|
if devMode:
|
||||||
# idempotent if logging has already been set up
|
# idempotent if logging has already been set up
|
||||||
|
@ -97,7 +98,7 @@ class MediaServer(threading.Thread):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/<path:pathin>", methods=["GET", "POST"])
|
@app.route("/<path:pathin>", methods=["GET", "POST"])
|
||||||
def allroutes(pathin):
|
def allroutes(pathin) -> Response:
|
||||||
try:
|
try:
|
||||||
directory, path = _redirectWebExports(pathin)
|
directory, path = _redirectWebExports(pathin)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
@ -171,7 +172,7 @@ def allroutes(pathin):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _redirectWebExports(path):
|
def _redirectWebExports(path) -> Tuple[str, str]:
|
||||||
# catch /_anki references and rewrite them to web export folder
|
# catch /_anki references and rewrite them to web export folder
|
||||||
targetPath = "_anki/"
|
targetPath = "_anki/"
|
||||||
if path.startswith(targetPath):
|
if path.startswith(targetPath):
|
||||||
|
|
|
@ -28,14 +28,14 @@ class LogEntryWithTime:
|
||||||
|
|
||||||
|
|
||||||
class MediaSyncer:
|
class MediaSyncer:
|
||||||
def __init__(self, mw: aqt.main.AnkiQt):
|
def __init__(self, mw: aqt.main.AnkiQt) -> None:
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self._syncing: bool = False
|
self._syncing: bool = False
|
||||||
self._log: List[LogEntryWithTime] = []
|
self._log: List[LogEntryWithTime] = []
|
||||||
self._progress_timer: Optional[QTimer] = None
|
self._progress_timer: Optional[QTimer] = None
|
||||||
gui_hooks.media_sync_did_start_or_stop.append(self._on_start_stop)
|
gui_hooks.media_sync_did_start_or_stop.append(self._on_start_stop)
|
||||||
|
|
||||||
def _on_progress(self):
|
def _on_progress(self) -> None:
|
||||||
progress = self.mw.col.latest_progress()
|
progress = self.mw.col.latest_progress()
|
||||||
if progress.kind != ProgressKind.MediaSync:
|
if progress.kind != ProgressKind.MediaSync:
|
||||||
return
|
return
|
||||||
|
@ -88,7 +88,7 @@ class MediaSyncer:
|
||||||
else:
|
else:
|
||||||
self._log_and_notify(tr(TR.SYNC_MEDIA_COMPLETE))
|
self._log_and_notify(tr(TR.SYNC_MEDIA_COMPLETE))
|
||||||
|
|
||||||
def _handle_sync_error(self, exc: BaseException):
|
def _handle_sync_error(self, exc: BaseException) -> None:
|
||||||
if isinstance(exc, Interrupted):
|
if isinstance(exc, Interrupted):
|
||||||
self._log_and_notify(tr(TR.SYNC_MEDIA_ABORTED))
|
self._log_and_notify(tr(TR.SYNC_MEDIA_ABORTED))
|
||||||
return
|
return
|
||||||
|
@ -116,10 +116,10 @@ class MediaSyncer:
|
||||||
def _on_start_stop(self, running: bool) -> None:
|
def _on_start_stop(self, running: bool) -> None:
|
||||||
self.mw.toolbar.set_sync_active(running)
|
self.mw.toolbar.set_sync_active(running)
|
||||||
|
|
||||||
def show_sync_log(self):
|
def show_sync_log(self) -> None:
|
||||||
aqt.dialogs.open("sync_log", self.mw, self)
|
aqt.dialogs.open("sync_log", self.mw, self)
|
||||||
|
|
||||||
def show_diag_until_finished(self, on_finished: Callable[[], None]):
|
def show_diag_until_finished(self, on_finished: Callable[[], None]) -> None:
|
||||||
# nothing to do if not syncing
|
# nothing to do if not syncing
|
||||||
if not self.is_syncing():
|
if not self.is_syncing():
|
||||||
return on_finished()
|
return on_finished()
|
||||||
|
@ -129,7 +129,7 @@ class MediaSyncer:
|
||||||
|
|
||||||
timer: Optional[QTimer] = None
|
timer: Optional[QTimer] = None
|
||||||
|
|
||||||
def check_finished():
|
def check_finished() -> None:
|
||||||
if not self.is_syncing():
|
if not self.is_syncing():
|
||||||
timer.stop()
|
timer.stop()
|
||||||
on_finished()
|
on_finished()
|
||||||
|
@ -197,7 +197,7 @@ class MediaSyncDialog(QDialog):
|
||||||
asctime = time.asctime(time.localtime(stamp))
|
asctime = time.asctime(time.localtime(stamp))
|
||||||
return f"{asctime}: {text}"
|
return f"{asctime}: {text}"
|
||||||
|
|
||||||
def _entry_to_text(self, entry: LogEntryWithTime):
|
def _entry_to_text(self, entry: LogEntryWithTime) -> str:
|
||||||
if isinstance(entry.entry, str):
|
if isinstance(entry.entry, str):
|
||||||
txt = entry.entry
|
txt = entry.entry
|
||||||
elif isinstance(entry.entry, MediaSyncProgress):
|
elif isinstance(entry.entry, MediaSyncProgress):
|
||||||
|
@ -209,7 +209,7 @@ class MediaSyncDialog(QDialog):
|
||||||
def _logentry_to_text(self, e: MediaSyncProgress) -> str:
|
def _logentry_to_text(self, e: MediaSyncProgress) -> str:
|
||||||
return f"{e.added}, {e.removed}, {e.checked}"
|
return f"{e.added}, {e.removed}, {e.checked}"
|
||||||
|
|
||||||
def _on_log_entry(self, entry: LogEntryWithTime):
|
def _on_log_entry(self, entry: LogEntryWithTime) -> None:
|
||||||
self.form.plainTextEdit.appendPlainText(self._entry_to_text(entry))
|
self.form.plainTextEdit.appendPlainText(self._entry_to_text(entry))
|
||||||
if not self._syncer.is_syncing():
|
if not self._syncer.is_syncing():
|
||||||
self.abort_button.setHidden(True)
|
self.abort_button.setHidden(True)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -74,7 +74,7 @@ class ModelChooser(QHBoxLayout):
|
||||||
# edit button
|
# edit button
|
||||||
edit = QPushButton(tr(TR.QT_MISC_MANAGE), clicked=self.onEdit) # type: ignore
|
edit = QPushButton(tr(TR.QT_MISC_MANAGE), clicked=self.onEdit) # type: ignore
|
||||||
|
|
||||||
def nameFunc():
|
def nameFunc() -> List[str]:
|
||||||
return sorted(self.deck.models.allNames())
|
return sorted(self.deck.models.allNames())
|
||||||
|
|
||||||
ret = StudyDeck(
|
ret = StudyDeck(
|
||||||
|
|
|
@ -219,7 +219,7 @@ class Models(QDialog):
|
||||||
class AddModel(QDialog):
|
class AddModel(QDialog):
|
||||||
model: Optional[NoteType]
|
model: Optional[NoteType]
|
||||||
|
|
||||||
def __init__(self, mw: AnkiQt, parent: Optional[QWidget] = None):
|
def __init__(self, mw: AnkiQt, parent: Optional[QWidget] = None) -> None:
|
||||||
self.parent_ = parent or mw
|
self.parent_ = parent or mw
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.col = mw.col
|
self.col = mw.col
|
||||||
|
|
|
@ -15,7 +15,7 @@ from aqt.utils import TR, askUserDialog, openLink, shortcut, tooltip, tr
|
||||||
|
|
||||||
|
|
||||||
class OverviewBottomBar:
|
class OverviewBottomBar:
|
||||||
def __init__(self, overview: Overview):
|
def __init__(self, overview: Overview) -> None:
|
||||||
self.overview = overview
|
self.overview = overview
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,12 +104,12 @@ class Overview:
|
||||||
def _filteredDeck(self) -> int:
|
def _filteredDeck(self) -> int:
|
||||||
return self.mw.col.decks.current()["dyn"]
|
return self.mw.col.decks.current()["dyn"]
|
||||||
|
|
||||||
def onRebuildKey(self):
|
def onRebuildKey(self) -> None:
|
||||||
if self._filteredDeck():
|
if self._filteredDeck():
|
||||||
self.mw.col.sched.rebuild_filtered_deck(self.mw.col.decks.selected())
|
self.mw.col.sched.rebuild_filtered_deck(self.mw.col.decks.selected())
|
||||||
self.mw.reset()
|
self.mw.reset()
|
||||||
|
|
||||||
def onEmptyKey(self):
|
def onEmptyKey(self) -> None:
|
||||||
if self._filteredDeck():
|
if self._filteredDeck():
|
||||||
self.mw.col.sched.empty_filtered_deck(self.mw.col.decks.selected())
|
self.mw.col.sched.empty_filtered_deck(self.mw.col.decks.selected())
|
||||||
self.mw.reset()
|
self.mw.reset()
|
||||||
|
@ -118,7 +118,7 @@ class Overview:
|
||||||
if not self._filteredDeck():
|
if not self._filteredDeck():
|
||||||
self.onStudyMore()
|
self.onStudyMore()
|
||||||
|
|
||||||
def onUnbury(self):
|
def onUnbury(self) -> None:
|
||||||
if self.mw.col.schedVer() == 1:
|
if self.mw.col.schedVer() == 1:
|
||||||
self.mw.col.sched.unburyCardsForDeck()
|
self.mw.col.sched.unburyCardsForDeck()
|
||||||
self.mw.reset()
|
self.mw.reset()
|
||||||
|
|
|
@ -34,7 +34,7 @@ def video_driver_name_for_platform(driver: VideoDriver) -> str:
|
||||||
|
|
||||||
|
|
||||||
class Preferences(QDialog):
|
class Preferences(QDialog):
|
||||||
def __init__(self, mw: AnkiQt):
|
def __init__(self, mw: AnkiQt) -> None:
|
||||||
QDialog.__init__(self, mw, Qt.Window)
|
QDialog.__init__(self, mw, Qt.Window)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.prof = self.mw.pm.profile
|
self.prof = self.mw.pm.profile
|
||||||
|
@ -55,7 +55,7 @@ class Preferences(QDialog):
|
||||||
self.setupOptions()
|
self.setupOptions()
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
# avoid exception if main window is already closed
|
# avoid exception if main window is already closed
|
||||||
if not self.mw.col:
|
if not self.mw.col:
|
||||||
return
|
return
|
||||||
|
@ -68,19 +68,19 @@ class Preferences(QDialog):
|
||||||
self.done(0)
|
self.done(0)
|
||||||
aqt.dialogs.markClosed("Preferences")
|
aqt.dialogs.markClosed("Preferences")
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
# Language
|
# Language
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def setupLang(self):
|
def setupLang(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
f.lang.addItems([x[0] for x in anki.lang.langs])
|
f.lang.addItems([x[0] for x in anki.lang.langs])
|
||||||
f.lang.setCurrentIndex(self.langIdx())
|
f.lang.setCurrentIndex(self.langIdx())
|
||||||
qconnect(f.lang.currentIndexChanged, self.onLangIdxChanged)
|
qconnect(f.lang.currentIndexChanged, self.onLangIdxChanged)
|
||||||
|
|
||||||
def langIdx(self):
|
def langIdx(self) -> int:
|
||||||
codes = [x[1] for x in anki.lang.langs]
|
codes = [x[1] for x in anki.lang.langs]
|
||||||
lang = anki.lang.currentLang
|
lang = anki.lang.currentLang
|
||||||
if lang in anki.lang.compatMap:
|
if lang in anki.lang.compatMap:
|
||||||
|
@ -92,7 +92,7 @@ class Preferences(QDialog):
|
||||||
except:
|
except:
|
||||||
return codes.index("en_US")
|
return codes.index("en_US")
|
||||||
|
|
||||||
def onLangIdxChanged(self, idx):
|
def onLangIdxChanged(self, idx) -> None:
|
||||||
code = anki.lang.langs[idx][1]
|
code = anki.lang.langs[idx][1]
|
||||||
self.mw.pm.setLang(code)
|
self.mw.pm.setLang(code)
|
||||||
showInfo(
|
showInfo(
|
||||||
|
@ -102,7 +102,7 @@ class Preferences(QDialog):
|
||||||
# Collection options
|
# Collection options
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def setupCollection(self):
|
def setupCollection(self) -> None:
|
||||||
import anki.consts as c
|
import anki.consts as c
|
||||||
|
|
||||||
f = self.form
|
f = self.form
|
||||||
|
@ -130,7 +130,7 @@ class Preferences(QDialog):
|
||||||
f.newSched.setChecked(True)
|
f.newSched.setChecked(True)
|
||||||
f.new_timezone.setChecked(s.new_timezone)
|
f.new_timezone.setChecked(s.new_timezone)
|
||||||
|
|
||||||
def setup_video_driver(self):
|
def setup_video_driver(self) -> None:
|
||||||
self.video_drivers = VideoDriver.all_for_platform()
|
self.video_drivers = VideoDriver.all_for_platform()
|
||||||
names = [
|
names = [
|
||||||
tr(TR.PREFERENCES_VIDEO_DRIVER, driver=video_driver_name_for_platform(d))
|
tr(TR.PREFERENCES_VIDEO_DRIVER, driver=video_driver_name_for_platform(d))
|
||||||
|
@ -141,13 +141,13 @@ class Preferences(QDialog):
|
||||||
self.video_drivers.index(self.mw.pm.video_driver())
|
self.video_drivers.index(self.mw.pm.video_driver())
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_video_driver(self):
|
def update_video_driver(self) -> None:
|
||||||
new_driver = self.video_drivers[self.form.video_driver.currentIndex()]
|
new_driver = self.video_drivers[self.form.video_driver.currentIndex()]
|
||||||
if new_driver != self.mw.pm.video_driver():
|
if new_driver != self.mw.pm.video_driver():
|
||||||
self.mw.pm.set_video_driver(new_driver)
|
self.mw.pm.set_video_driver(new_driver)
|
||||||
showInfo(tr(TR.PREFERENCES_CHANGES_WILL_TAKE_EFFECT_WHEN_YOU))
|
showInfo(tr(TR.PREFERENCES_CHANGES_WILL_TAKE_EFFECT_WHEN_YOU))
|
||||||
|
|
||||||
def updateCollection(self):
|
def updateCollection(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
d = self.mw.col
|
d = self.mw.col
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ class Preferences(QDialog):
|
||||||
# Scheduler version
|
# Scheduler version
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def _updateSchedVer(self, wantNew):
|
def _updateSchedVer(self, wantNew) -> None:
|
||||||
haveNew = self.mw.col.schedVer() == 2
|
haveNew = self.mw.col.schedVer() == 2
|
||||||
|
|
||||||
# nothing to do?
|
# nothing to do?
|
||||||
|
@ -194,7 +194,7 @@ class Preferences(QDialog):
|
||||||
# Network
|
# Network
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def setupNetwork(self):
|
def setupNetwork(self) -> None:
|
||||||
self.form.media_log.setText(tr(TR.SYNC_MEDIA_LOG_BUTTON))
|
self.form.media_log.setText(tr(TR.SYNC_MEDIA_LOG_BUTTON))
|
||||||
qconnect(self.form.media_log.clicked, self.on_media_log)
|
qconnect(self.form.media_log.clicked, self.on_media_log)
|
||||||
self.form.syncOnProgramOpen.setChecked(self.prof["autoSync"])
|
self.form.syncOnProgramOpen.setChecked(self.prof["autoSync"])
|
||||||
|
@ -207,10 +207,10 @@ class Preferences(QDialog):
|
||||||
qconnect(self.form.syncDeauth.clicked, self.onSyncDeauth)
|
qconnect(self.form.syncDeauth.clicked, self.onSyncDeauth)
|
||||||
self.form.syncDeauth.setText(tr(TR.SYNC_LOG_OUT_BUTTON))
|
self.form.syncDeauth.setText(tr(TR.SYNC_LOG_OUT_BUTTON))
|
||||||
|
|
||||||
def on_media_log(self):
|
def on_media_log(self) -> None:
|
||||||
self.mw.media_syncer.show_sync_log()
|
self.mw.media_syncer.show_sync_log()
|
||||||
|
|
||||||
def _hideAuth(self):
|
def _hideAuth(self) -> None:
|
||||||
self.form.syncDeauth.setVisible(False)
|
self.form.syncDeauth.setVisible(False)
|
||||||
self.form.syncUser.setText("")
|
self.form.syncUser.setText("")
|
||||||
self.form.syncLabel.setText(
|
self.form.syncLabel.setText(
|
||||||
|
@ -225,7 +225,7 @@ class Preferences(QDialog):
|
||||||
self.mw.col.media.force_resync()
|
self.mw.col.media.force_resync()
|
||||||
self._hideAuth()
|
self._hideAuth()
|
||||||
|
|
||||||
def updateNetwork(self):
|
def updateNetwork(self) -> None:
|
||||||
self.prof["autoSync"] = self.form.syncOnProgramOpen.isChecked()
|
self.prof["autoSync"] = self.form.syncOnProgramOpen.isChecked()
|
||||||
self.prof["syncMedia"] = self.form.syncMedia.isChecked()
|
self.prof["syncMedia"] = self.form.syncMedia.isChecked()
|
||||||
self.mw.pm.set_auto_sync_media_minutes(
|
self.mw.pm.set_auto_sync_media_minutes(
|
||||||
|
@ -238,16 +238,16 @@ class Preferences(QDialog):
|
||||||
# Backup
|
# Backup
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def setupBackup(self):
|
def setupBackup(self) -> None:
|
||||||
self.form.numBackups.setValue(self.prof["numBackups"])
|
self.form.numBackups.setValue(self.prof["numBackups"])
|
||||||
|
|
||||||
def updateBackup(self):
|
def updateBackup(self) -> None:
|
||||||
self.prof["numBackups"] = self.form.numBackups.value()
|
self.prof["numBackups"] = self.form.numBackups.value()
|
||||||
|
|
||||||
# Basic & Advanced Options
|
# Basic & Advanced Options
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def setupOptions(self):
|
def setupOptions(self) -> None:
|
||||||
self.form.pastePNG.setChecked(self.prof.get("pastePNG", False))
|
self.form.pastePNG.setChecked(self.prof.get("pastePNG", False))
|
||||||
self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100))
|
self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100))
|
||||||
self.form.pasteInvert.setChecked(self.prof.get("pasteInvert", False))
|
self.form.pasteInvert.setChecked(self.prof.get("pasteInvert", False))
|
||||||
|
@ -270,7 +270,7 @@ class Preferences(QDialog):
|
||||||
self._recording_drivers.index(self.mw.pm.recording_driver())
|
self._recording_drivers.index(self.mw.pm.recording_driver())
|
||||||
)
|
)
|
||||||
|
|
||||||
def updateOptions(self):
|
def updateOptions(self) -> None:
|
||||||
restart_required = False
|
restart_required = False
|
||||||
|
|
||||||
self.prof["pastePNG"] = self.form.pastePNG.isChecked()
|
self.prof["pastePNG"] = self.form.pastePNG.isChecked()
|
||||||
|
|
|
@ -40,7 +40,9 @@ class Previewer(QDialog):
|
||||||
_timer: Optional[QTimer] = None
|
_timer: Optional[QTimer] = None
|
||||||
_show_both_sides = False
|
_show_both_sides = False
|
||||||
|
|
||||||
def __init__(self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None]):
|
def __init__(
|
||||||
|
self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None]
|
||||||
|
) -> None:
|
||||||
super().__init__(None, Qt.Window)
|
super().__init__(None, Qt.Window)
|
||||||
self._open = True
|
self._open = True
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
|
@ -259,14 +261,14 @@ class MultiCardPreviewer(Previewer):
|
||||||
qconnect(self._prev.clicked, self._on_prev)
|
qconnect(self._prev.clicked, self._on_prev)
|
||||||
qconnect(self._next.clicked, self._on_next)
|
qconnect(self._next.clicked, self._on_next)
|
||||||
|
|
||||||
def _on_prev(self):
|
def _on_prev(self) -> None:
|
||||||
if self._state == "answer" and not self._show_both_sides:
|
if self._state == "answer" and not self._show_both_sides:
|
||||||
self._state = "question"
|
self._state = "question"
|
||||||
self.render_card()
|
self.render_card()
|
||||||
else:
|
else:
|
||||||
self._on_prev_card()
|
self._on_prev_card()
|
||||||
|
|
||||||
def _on_prev_card(self):
|
def _on_prev_card(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _on_next(self) -> None:
|
def _on_next(self) -> None:
|
||||||
|
@ -276,7 +278,7 @@ class MultiCardPreviewer(Previewer):
|
||||||
else:
|
else:
|
||||||
self._on_next_card()
|
self._on_next_card()
|
||||||
|
|
||||||
def _on_next_card(self):
|
def _on_next_card(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _updateButtons(self) -> None:
|
def _updateButtons(self) -> None:
|
||||||
|
@ -315,7 +317,7 @@ class BrowserPreviewer(MultiCardPreviewer):
|
||||||
self._last_card_id = c.id
|
self._last_card_id = c.id
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def _on_prev_card(self):
|
def _on_prev_card(self) -> None:
|
||||||
self._parent.editor.saveNow(
|
self._parent.editor.saveNow(
|
||||||
lambda: self._parent._moveCur(QAbstractItemView.MoveUp)
|
lambda: self._parent._moveCur(QAbstractItemView.MoveUp)
|
||||||
)
|
)
|
||||||
|
|
|
@ -113,13 +113,13 @@ class LoadMetaResult:
|
||||||
|
|
||||||
|
|
||||||
class AnkiRestart(SystemExit):
|
class AnkiRestart(SystemExit):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
self.exitcode = kwargs.pop("exitcode", 0)
|
self.exitcode = kwargs.pop("exitcode", 0)
|
||||||
super().__init__(*args, **kwargs) # type: ignore
|
super().__init__(*args, **kwargs) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class ProfileManager:
|
class ProfileManager:
|
||||||
def __init__(self, base: Optional[str] = None) -> None:
|
def __init__(self, base: Optional[str] = None) -> None: #
|
||||||
## Settings which should be forgotten each Anki restart
|
## Settings which should be forgotten each Anki restart
|
||||||
self.session: Dict[str, Any] = {}
|
self.session: Dict[str, Any] = {}
|
||||||
self.name: Optional[str] = None
|
self.name: Optional[str] = None
|
||||||
|
@ -185,7 +185,7 @@ class ProfileManager:
|
||||||
self.base = newBase
|
self.base = newBase
|
||||||
shutil.move(oldBase, self.base)
|
shutil.move(oldBase, self.base)
|
||||||
|
|
||||||
def _tryToMigrateFolder(self, oldBase):
|
def _tryToMigrateFolder(self, oldBase) -> None:
|
||||||
from PyQt5 import QtGui, QtWidgets
|
from PyQt5 import QtGui, QtWidgets
|
||||||
|
|
||||||
app = QtWidgets.QApplication([])
|
app = QtWidgets.QApplication([])
|
||||||
|
@ -269,7 +269,7 @@ class ProfileManager:
|
||||||
fn = super().find_class(module, name)
|
fn = super().find_class(module, name)
|
||||||
if module == "sip" and name == "_unpickle_type":
|
if module == "sip" and name == "_unpickle_type":
|
||||||
|
|
||||||
def wrapper(mod, obj, args):
|
def wrapper(mod, obj, args) -> Any:
|
||||||
if mod.startswith("PyQt4") and obj == "QByteArray":
|
if mod.startswith("PyQt4") and obj == "QByteArray":
|
||||||
# can't trust str objects from python 2
|
# can't trust str objects from python 2
|
||||||
return QByteArray()
|
return QByteArray()
|
||||||
|
@ -534,7 +534,7 @@ create table if not exists profiles
|
||||||
def setDefaultLang(self, idx: int) -> None:
|
def setDefaultLang(self, idx: int) -> None:
|
||||||
# create dialog
|
# create dialog
|
||||||
class NoCloseDiag(QDialog):
|
class NoCloseDiag(QDialog):
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
d = self.langDiag = NoCloseDiag()
|
d = self.langDiag = NoCloseDiag()
|
||||||
|
@ -665,7 +665,7 @@ create table if not exists profiles
|
||||||
pass
|
pass
|
||||||
return RecordingDriver.QtAudioInput
|
return RecordingDriver.QtAudioInput
|
||||||
|
|
||||||
def set_recording_driver(self, driver: RecordingDriver):
|
def set_recording_driver(self, driver: RecordingDriver) -> None:
|
||||||
self.profile["recordingDriver"] = driver.value
|
self.profile["recordingDriver"] = driver.value
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
|
@ -43,7 +43,7 @@ class ProgressManager:
|
||||||
timer to fire even when there is no collection, but will still
|
timer to fire even when there is no collection, but will still
|
||||||
only fire when there is no current progress dialog."""
|
only fire when there is no current progress dialog."""
|
||||||
|
|
||||||
def handler():
|
def handler() -> None:
|
||||||
if requiresCollection and not self.mw.col:
|
if requiresCollection and not self.mw.col:
|
||||||
# no current collection; timer is no longer valid
|
# no current collection; timer is no longer valid
|
||||||
print("Ignored progress func as collection unloaded: %s" % repr(func))
|
print("Ignored progress func as collection unloaded: %s" % repr(func))
|
||||||
|
@ -225,14 +225,14 @@ class ProgressDialog(QDialog):
|
||||||
self._closingDown = True
|
self._closingDown = True
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
def closeEvent(self, evt):
|
def closeEvent(self, evt) -> None:
|
||||||
if self._closingDown:
|
if self._closingDown:
|
||||||
evt.accept()
|
evt.accept()
|
||||||
else:
|
else:
|
||||||
self.wantCancel = True
|
self.wantCancel = True
|
||||||
evt.ignore()
|
evt.ignore()
|
||||||
|
|
||||||
def keyPressEvent(self, evt):
|
def keyPressEvent(self, evt) -> None:
|
||||||
if evt.key() == Qt.Key_Escape:
|
if evt.key() == Qt.Key_Escape:
|
||||||
evt.ignore()
|
evt.ignore()
|
||||||
self.wantCancel = True
|
self.wantCancel = True
|
||||||
|
|
|
@ -30,7 +30,7 @@ except ImportError:
|
||||||
import sip # type: ignore
|
import sip # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def debug():
|
def debug() -> None:
|
||||||
from pdb import set_trace
|
from pdb import set_trace
|
||||||
|
|
||||||
pyqtRemoveInputHook()
|
pyqtRemoveInputHook()
|
||||||
|
@ -39,7 +39,7 @@ def debug():
|
||||||
|
|
||||||
if os.environ.get("DEBUG"):
|
if os.environ.get("DEBUG"):
|
||||||
|
|
||||||
def info(type, value, tb):
|
def info(type, value, tb) -> None:
|
||||||
for line in traceback.format_exception(type, value, tb):
|
for line in traceback.format_exception(type, value, tb):
|
||||||
sys.stdout.write(line)
|
sys.stdout.write(line)
|
||||||
pyqtRemoveInputHook()
|
pyqtRemoveInputHook()
|
||||||
|
|
|
@ -8,7 +8,7 @@ import html
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import unicodedata as ucd
|
import unicodedata as ucd
|
||||||
from typing import Any, Callable, List, Optional, Tuple, Union
|
from typing import Any, Callable, List, Match, Optional, Tuple, Union
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
@ -426,7 +426,7 @@ class Reviewer:
|
||||||
# compare with typed answer
|
# compare with typed answer
|
||||||
res = self.correct(given, cor, showBad=False)
|
res = self.correct(given, cor, showBad=False)
|
||||||
# and update the type answer area
|
# and update the type answer area
|
||||||
def repl(match):
|
def repl(match: Match) -> str:
|
||||||
# can't pass a string in directly, and can't use re.escape as it
|
# can't pass a string in directly, and can't use re.escape as it
|
||||||
# escapes too much
|
# escapes too much
|
||||||
s = """
|
s = """
|
||||||
|
@ -448,7 +448,7 @@ class Reviewer:
|
||||||
if not matches:
|
if not matches:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def noHint(txt):
|
def noHint(txt) -> str:
|
||||||
if "::" in txt:
|
if "::" in txt:
|
||||||
return txt.split("::")[0]
|
return txt.split("::")[0]
|
||||||
return txt
|
return txt
|
||||||
|
@ -652,7 +652,7 @@ time = %(time)d;
|
||||||
def _answerButtons(self) -> str:
|
def _answerButtons(self) -> str:
|
||||||
default = self._defaultEase()
|
default = self._defaultEase()
|
||||||
|
|
||||||
def but(i, label):
|
def but(i, label) -> str:
|
||||||
if i == default:
|
if i == default:
|
||||||
extra = """id="defease" class="focus" """
|
extra = """id="defease" class="focus" """
|
||||||
else:
|
else:
|
||||||
|
@ -834,7 +834,7 @@ time = %(time)d;
|
||||||
tooltip(tr(TR.STUDYING_NOTE_BURIED))
|
tooltip(tr(TR.STUDYING_NOTE_BURIED))
|
||||||
|
|
||||||
def onRecordVoice(self) -> None:
|
def onRecordVoice(self) -> None:
|
||||||
def after_record(path: str):
|
def after_record(path: str) -> None:
|
||||||
self._recordedAudio = path
|
self._recordedAudio = path
|
||||||
self.onReplayRecorded()
|
self.onReplayRecorded()
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Change(enum.Enum):
|
||||||
class ChangeTracker:
|
class ChangeTracker:
|
||||||
_changed = Change.NO_CHANGE
|
_changed = Change.NO_CHANGE
|
||||||
|
|
||||||
def __init__(self, mw: AnkiQt):
|
def __init__(self, mw: AnkiQt) -> None:
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
|
||||||
def mark_basic(self) -> None:
|
def mark_basic(self) -> None:
|
||||||
|
|
|
@ -438,7 +438,7 @@ class MpvManager(MPV, SoundOrVideoPlayer):
|
||||||
|
|
||||||
|
|
||||||
class SimpleMplayerSlaveModePlayer(SimpleMplayerPlayer):
|
class SimpleMplayerSlaveModePlayer(SimpleMplayerPlayer):
|
||||||
def __init__(self, taskman: TaskManager):
|
def __init__(self, taskman: TaskManager) -> None:
|
||||||
super().__init__(taskman)
|
super().__init__(taskman)
|
||||||
self.args.append("-slave")
|
self.args.append("-slave")
|
||||||
|
|
||||||
|
@ -494,7 +494,7 @@ def encode_mp3(mw: aqt.AnkiQt, src_wav: str, on_done: Callable[[str], None]) ->
|
||||||
"Encode the provided wav file to .mp3, and call on_done() with the path."
|
"Encode the provided wav file to .mp3, and call on_done() with the path."
|
||||||
dst_mp3 = src_wav.replace(".wav", "%d.mp3" % time.time())
|
dst_mp3 = src_wav.replace(".wav", "%d.mp3" % time.time())
|
||||||
|
|
||||||
def _on_done(fut: Future):
|
def _on_done(fut: Future) -> None:
|
||||||
fut.result()
|
fut.result()
|
||||||
on_done(dst_mp3)
|
on_done(dst_mp3)
|
||||||
|
|
||||||
|
@ -509,7 +509,7 @@ class Recorder(ABC):
|
||||||
# seconds to wait before recording
|
# seconds to wait before recording
|
||||||
STARTUP_DELAY = 0.3
|
STARTUP_DELAY = 0.3
|
||||||
|
|
||||||
def __init__(self, output_path: str):
|
def __init__(self, output_path: str) -> None:
|
||||||
self.output_path = output_path
|
self.output_path = output_path
|
||||||
|
|
||||||
def start(self, on_done: Callable[[], None]) -> None:
|
def start(self, on_done: Callable[[], None]) -> None:
|
||||||
|
@ -517,7 +517,7 @@ class Recorder(ABC):
|
||||||
self._started_at = time.time()
|
self._started_at = time.time()
|
||||||
on_done()
|
on_done()
|
||||||
|
|
||||||
def stop(self, on_done: Callable[[str], None]):
|
def stop(self, on_done: Callable[[str], None]) -> None:
|
||||||
"Stop recording, then call on_done() when finished."
|
"Stop recording, then call on_done() when finished."
|
||||||
on_done(self.output_path)
|
on_done(self.output_path)
|
||||||
|
|
||||||
|
@ -525,7 +525,7 @@ class Recorder(ABC):
|
||||||
"Seconds since recording started."
|
"Seconds since recording started."
|
||||||
return time.time() - self._started_at
|
return time.time() - self._started_at
|
||||||
|
|
||||||
def on_timer(self):
|
def on_timer(self) -> None:
|
||||||
"Will be called periodically."
|
"Will be called periodically."
|
||||||
|
|
||||||
|
|
||||||
|
@ -534,7 +534,7 @@ class Recorder(ABC):
|
||||||
|
|
||||||
|
|
||||||
class QtAudioInputRecorder(Recorder):
|
class QtAudioInputRecorder(Recorder):
|
||||||
def __init__(self, output_path: str, mw: aqt.AnkiQt, parent: QWidget):
|
def __init__(self, output_path: str, mw: aqt.AnkiQt, parent: QWidget) -> None:
|
||||||
super().__init__(output_path)
|
super().__init__(output_path)
|
||||||
|
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
@ -567,11 +567,11 @@ class QtAudioInputRecorder(Recorder):
|
||||||
self._iodevice.readyRead.connect(self._on_read_ready) # type: ignore
|
self._iodevice.readyRead.connect(self._on_read_ready) # type: ignore
|
||||||
super().start(on_done)
|
super().start(on_done)
|
||||||
|
|
||||||
def _on_read_ready(self):
|
def _on_read_ready(self) -> None:
|
||||||
self._buffer += self._iodevice.readAll()
|
self._buffer += self._iodevice.readAll()
|
||||||
|
|
||||||
def stop(self, on_done: Callable[[str], None]):
|
def stop(self, on_done: Callable[[str], None]) -> None:
|
||||||
def on_stop_timer():
|
def on_stop_timer() -> None:
|
||||||
# read anything remaining in buffer & stop
|
# read anything remaining in buffer & stop
|
||||||
self._on_read_ready()
|
self._on_read_ready()
|
||||||
self._audio_input.stop()
|
self._audio_input.stop()
|
||||||
|
@ -580,7 +580,7 @@ class QtAudioInputRecorder(Recorder):
|
||||||
showWarning(f"recording failed: {err}")
|
showWarning(f"recording failed: {err}")
|
||||||
return
|
return
|
||||||
|
|
||||||
def write_file():
|
def write_file() -> None:
|
||||||
# swallow the first 300ms to allow audio device to quiesce
|
# swallow the first 300ms to allow audio device to quiesce
|
||||||
wait = int(44100 * self.STARTUP_DELAY)
|
wait = int(44100 * self.STARTUP_DELAY)
|
||||||
if len(self._buffer) <= wait:
|
if len(self._buffer) <= wait:
|
||||||
|
@ -595,7 +595,7 @@ class QtAudioInputRecorder(Recorder):
|
||||||
wf.writeframes(self._buffer)
|
wf.writeframes(self._buffer)
|
||||||
wf.close()
|
wf.close()
|
||||||
|
|
||||||
def and_then(fut):
|
def and_then(fut) -> None:
|
||||||
fut.result()
|
fut.result()
|
||||||
Recorder.stop(self, on_done)
|
Recorder.stop(self, on_done)
|
||||||
|
|
||||||
|
@ -672,7 +672,7 @@ class PyAudioThreadedRecorder(threading.Thread):
|
||||||
|
|
||||||
|
|
||||||
class PyAudioRecorder(Recorder):
|
class PyAudioRecorder(Recorder):
|
||||||
def __init__(self, mw: aqt.AnkiQt, output_path: str):
|
def __init__(self, mw: aqt.AnkiQt, output_path: str) -> None:
|
||||||
super().__init__(output_path)
|
super().__init__(output_path)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
|
||||||
|
@ -686,7 +686,7 @@ class PyAudioRecorder(Recorder):
|
||||||
while self.duration() < 1:
|
while self.duration() < 1:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
def func(fut):
|
def func(fut) -> None:
|
||||||
Recorder.stop(self, on_done)
|
Recorder.stop(self, on_done)
|
||||||
|
|
||||||
self.thread.finish = True
|
self.thread.finish = True
|
||||||
|
@ -715,7 +715,7 @@ class RecordDialog(QDialog):
|
||||||
self._start_recording()
|
self._start_recording()
|
||||||
self._setup_dialog()
|
self._setup_dialog()
|
||||||
|
|
||||||
def _setup_dialog(self):
|
def _setup_dialog(self) -> None:
|
||||||
self.setWindowTitle("Anki")
|
self.setWindowTitle("Anki")
|
||||||
icon = QLabel()
|
icon = QLabel()
|
||||||
icon.setPixmap(QPixmap(":/icons/media-record.png"))
|
icon.setPixmap(QPixmap(":/icons/media-record.png"))
|
||||||
|
@ -740,10 +740,10 @@ class RecordDialog(QDialog):
|
||||||
restoreGeom(self, "audioRecorder2")
|
restoreGeom(self, "audioRecorder2")
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def _save_diag(self):
|
def _save_diag(self) -> None:
|
||||||
saveGeom(self, "audioRecorder2")
|
saveGeom(self, "audioRecorder2")
|
||||||
|
|
||||||
def _start_recording(self):
|
def _start_recording(self) -> None:
|
||||||
driver = self.mw.pm.recording_driver()
|
driver = self.mw.pm.recording_driver()
|
||||||
if driver is RecordingDriver.PyAudio:
|
if driver is RecordingDriver.PyAudio:
|
||||||
self._recorder = PyAudioRecorder(self.mw, namedtmp("rec.wav"))
|
self._recorder = PyAudioRecorder(self.mw, namedtmp("rec.wav"))
|
||||||
|
@ -755,18 +755,18 @@ class RecordDialog(QDialog):
|
||||||
assert_exhaustive(driver)
|
assert_exhaustive(driver)
|
||||||
self._recorder.start(self._start_timer)
|
self._recorder.start(self._start_timer)
|
||||||
|
|
||||||
def _start_timer(self):
|
def _start_timer(self) -> None:
|
||||||
self._timer = t = QTimer(self._parent)
|
self._timer = t = QTimer(self._parent)
|
||||||
t.timeout.connect(self._on_timer) # type: ignore
|
t.timeout.connect(self._on_timer) # type: ignore
|
||||||
t.setSingleShot(False)
|
t.setSingleShot(False)
|
||||||
t.start(100)
|
t.start(100)
|
||||||
|
|
||||||
def _on_timer(self):
|
def _on_timer(self) -> None:
|
||||||
self._recorder.on_timer()
|
self._recorder.on_timer()
|
||||||
duration = self._recorder.duration()
|
duration = self._recorder.duration()
|
||||||
self.label.setText(tr(TR.MEDIA_RECORDINGTIME, secs="%0.1f" % duration))
|
self.label.setText(tr(TR.MEDIA_RECORDINGTIME, secs="%0.1f" % duration))
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
self._timer.stop()
|
self._timer.stop()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -775,10 +775,10 @@ class RecordDialog(QDialog):
|
||||||
finally:
|
finally:
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self._timer.stop()
|
self._timer.stop()
|
||||||
|
|
||||||
def cleanup(out: str):
|
def cleanup(out: str) -> None:
|
||||||
os.unlink(out)
|
os.unlink(out)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -790,7 +790,7 @@ class RecordDialog(QDialog):
|
||||||
def record_audio(
|
def record_audio(
|
||||||
parent: QWidget, mw: aqt.AnkiQt, encode: bool, on_done: Callable[[str], None]
|
parent: QWidget, mw: aqt.AnkiQt, encode: bool, on_done: Callable[[str], None]
|
||||||
):
|
):
|
||||||
def after_record(path: str):
|
def after_record(path: str) -> None:
|
||||||
if not encode:
|
if not encode:
|
||||||
on_done(path)
|
on_done(path)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -25,7 +25,7 @@ from aqt.utils import (
|
||||||
class NewDeckStats(QDialog):
|
class NewDeckStats(QDialog):
|
||||||
"""New deck stats."""
|
"""New deck stats."""
|
||||||
|
|
||||||
def __init__(self, mw: aqt.main.AnkiQt):
|
def __init__(self, mw: aqt.main.AnkiQt) -> None:
|
||||||
QDialog.__init__(self, mw, Qt.Window)
|
QDialog.__init__(self, mw, Qt.Window)
|
||||||
mw.setupDialogGC(self)
|
mw.setupDialogGC(self)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
@ -60,11 +60,11 @@ class NewDeckStats(QDialog):
|
||||||
aqt.dialogs.markClosed("NewDeckStats")
|
aqt.dialogs.markClosed("NewDeckStats")
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def closeWithCallback(self, callback):
|
def closeWithCallback(self, callback) -> None:
|
||||||
self.reject()
|
self.reject()
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
def _imagePath(self):
|
def _imagePath(self) -> str:
|
||||||
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
||||||
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
||||||
file = getSaveFile(
|
file = getSaveFile(
|
||||||
|
@ -77,17 +77,17 @@ class NewDeckStats(QDialog):
|
||||||
)
|
)
|
||||||
return file
|
return file
|
||||||
|
|
||||||
def saveImage(self):
|
def saveImage(self) -> None:
|
||||||
path = self._imagePath()
|
path = self._imagePath()
|
||||||
if not path:
|
if not path:
|
||||||
return
|
return
|
||||||
self.form.web.page().printToPdf(path)
|
self.form.web.page().printToPdf(path)
|
||||||
tooltip(tr(TR.STATISTICS_SAVED))
|
tooltip(tr(TR.STATISTICS_SAVED))
|
||||||
|
|
||||||
def changePeriod(self, n):
|
def changePeriod(self, n) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def changeScope(self, type):
|
def changeScope(self, type) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _on_bridge_cmd(self, cmd: str) -> bool:
|
def _on_bridge_cmd(self, cmd: str) -> bool:
|
||||||
|
@ -149,11 +149,11 @@ class DeckStats(QDialog):
|
||||||
aqt.dialogs.markClosed("DeckStats")
|
aqt.dialogs.markClosed("DeckStats")
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def closeWithCallback(self, callback):
|
def closeWithCallback(self, callback) -> None:
|
||||||
self.reject()
|
self.reject()
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
def _imagePath(self):
|
def _imagePath(self) -> str:
|
||||||
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
|
||||||
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
name = "anki-" + tr(TR.STATISTICS_STATS) + name
|
||||||
file = getSaveFile(
|
file = getSaveFile(
|
||||||
|
@ -166,7 +166,7 @@ class DeckStats(QDialog):
|
||||||
)
|
)
|
||||||
return file
|
return file
|
||||||
|
|
||||||
def saveImage(self):
|
def saveImage(self) -> None:
|
||||||
path = self._imagePath()
|
path = self._imagePath()
|
||||||
if not path:
|
if not path:
|
||||||
return
|
return
|
||||||
|
|
|
@ -135,7 +135,7 @@ class StudyDeck(QDialog):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def onReset(self):
|
def onReset(self) -> None:
|
||||||
# model updated?
|
# model updated?
|
||||||
if self.nameFunc:
|
if self.nameFunc:
|
||||||
self.origNames = self.nameFunc()
|
self.origNames = self.nameFunc()
|
||||||
|
|
|
@ -40,12 +40,14 @@ class FullSyncChoice(enum.Enum):
|
||||||
DOWNLOAD = 2
|
DOWNLOAD = 2
|
||||||
|
|
||||||
|
|
||||||
def get_sync_status(mw: aqt.main.AnkiQt, callback: Callable[[SyncStatus], None]):
|
def get_sync_status(
|
||||||
|
mw: aqt.main.AnkiQt, callback: Callable[[SyncStatus], None]
|
||||||
|
) -> None:
|
||||||
auth = mw.pm.sync_auth()
|
auth = mw.pm.sync_auth()
|
||||||
if not auth:
|
if not auth:
|
||||||
return SyncStatus(required=SyncStatus.NO_CHANGES) # pylint:disable=no-member
|
callback(SyncStatus(required=SyncStatus.NO_CHANGES)) # pylint:disable=no-member
|
||||||
|
|
||||||
def on_future_done(fut):
|
def on_future_done(fut) -> None:
|
||||||
try:
|
try:
|
||||||
out = fut.result()
|
out = fut.result()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -57,7 +59,7 @@ def get_sync_status(mw: aqt.main.AnkiQt, callback: Callable[[SyncStatus], None])
|
||||||
mw.taskman.run_in_background(lambda: mw.col.sync_status(auth), on_future_done)
|
mw.taskman.run_in_background(lambda: mw.col.sync_status(auth), on_future_done)
|
||||||
|
|
||||||
|
|
||||||
def handle_sync_error(mw: aqt.main.AnkiQt, err: Exception):
|
def handle_sync_error(mw: aqt.main.AnkiQt, err: Exception) -> None:
|
||||||
if isinstance(err, SyncError):
|
if isinstance(err, SyncError):
|
||||||
if err.is_auth_error():
|
if err.is_auth_error():
|
||||||
mw.pm.clear_sync_auth()
|
mw.pm.clear_sync_auth()
|
||||||
|
@ -87,14 +89,14 @@ def sync_collection(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
||||||
auth = mw.pm.sync_auth()
|
auth = mw.pm.sync_auth()
|
||||||
assert auth
|
assert auth
|
||||||
|
|
||||||
def on_timer():
|
def on_timer() -> None:
|
||||||
on_normal_sync_timer(mw)
|
on_normal_sync_timer(mw)
|
||||||
|
|
||||||
timer = QTimer(mw)
|
timer = QTimer(mw)
|
||||||
qconnect(timer.timeout, on_timer)
|
qconnect(timer.timeout, on_timer)
|
||||||
timer.start(150)
|
timer.start(150)
|
||||||
|
|
||||||
def on_future_done(fut):
|
def on_future_done(fut) -> None:
|
||||||
mw.col.db.begin()
|
mw.col.db.begin()
|
||||||
timer.stop()
|
timer.stop()
|
||||||
try:
|
try:
|
||||||
|
@ -171,14 +173,14 @@ def on_full_sync_timer(mw: aqt.main.AnkiQt) -> None:
|
||||||
def full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
def full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
||||||
mw.col.close_for_full_sync()
|
mw.col.close_for_full_sync()
|
||||||
|
|
||||||
def on_timer():
|
def on_timer() -> None:
|
||||||
on_full_sync_timer(mw)
|
on_full_sync_timer(mw)
|
||||||
|
|
||||||
timer = QTimer(mw)
|
timer = QTimer(mw)
|
||||||
qconnect(timer.timeout, on_timer)
|
qconnect(timer.timeout, on_timer)
|
||||||
timer.start(150)
|
timer.start(150)
|
||||||
|
|
||||||
def on_future_done(fut):
|
def on_future_done(fut) -> None:
|
||||||
timer.stop()
|
timer.stop()
|
||||||
mw.col.reopen(after_full_sync=True)
|
mw.col.reopen(after_full_sync=True)
|
||||||
mw.reset()
|
mw.reset()
|
||||||
|
@ -199,14 +201,14 @@ def full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
||||||
def full_upload(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
def full_upload(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
|
||||||
mw.col.close_for_full_sync()
|
mw.col.close_for_full_sync()
|
||||||
|
|
||||||
def on_timer():
|
def on_timer() -> None:
|
||||||
on_full_sync_timer(mw)
|
on_full_sync_timer(mw)
|
||||||
|
|
||||||
timer = QTimer(mw)
|
timer = QTimer(mw)
|
||||||
qconnect(timer.timeout, on_timer)
|
qconnect(timer.timeout, on_timer)
|
||||||
timer.start(150)
|
timer.start(150)
|
||||||
|
|
||||||
def on_future_done(fut):
|
def on_future_done(fut) -> None:
|
||||||
timer.stop()
|
timer.stop()
|
||||||
mw.col.reopen(after_full_sync=True)
|
mw.col.reopen(after_full_sync=True)
|
||||||
mw.reset()
|
mw.reset()
|
||||||
|
@ -235,7 +237,7 @@ def sync_login(
|
||||||
if username and password:
|
if username and password:
|
||||||
break
|
break
|
||||||
|
|
||||||
def on_future_done(fut):
|
def on_future_done(fut) -> None:
|
||||||
try:
|
try:
|
||||||
auth = fut.result()
|
auth = fut.result()
|
||||||
except SyncError as e:
|
except SyncError as e:
|
||||||
|
|
|
@ -68,7 +68,7 @@ class TagLimit(QDialog):
|
||||||
idx = self.dialog.inactiveList.indexFromItem(item)
|
idx = self.dialog.inactiveList.indexFromItem(item)
|
||||||
self.dialog.inactiveList.selectionModel().select(idx, mode)
|
self.dialog.inactiveList.selectionModel().select(idx, mode)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.tags = ""
|
self.tags = ""
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class TaskManager(QObject):
|
||||||
self._closures_lock = Lock()
|
self._closures_lock = Lock()
|
||||||
qconnect(self._closures_pending, self._on_closures_pending)
|
qconnect(self._closures_pending, self._on_closures_pending)
|
||||||
|
|
||||||
def run_on_main(self, closure: Closure):
|
def run_on_main(self, closure: Closure) -> None:
|
||||||
"Run the provided closure on the main thread."
|
"Run the provided closure on the main thread."
|
||||||
with self._closures_lock:
|
with self._closures_lock:
|
||||||
self._closures.append(closure)
|
self._closures.append(closure)
|
||||||
|
@ -71,7 +71,7 @@ class TaskManager(QObject):
|
||||||
):
|
):
|
||||||
self.mw.progress.start(parent=parent, label=label, immediate=immediate)
|
self.mw.progress.start(parent=parent, label=label, immediate=immediate)
|
||||||
|
|
||||||
def wrapped_done(fut):
|
def wrapped_done(fut) -> None:
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
if on_done:
|
if on_done:
|
||||||
on_done(fut)
|
on_done(fut)
|
||||||
|
|
|
@ -481,7 +481,7 @@ if isWin:
|
||||||
return []
|
return []
|
||||||
return list(map(self._voice_to_object, self.speaker.GetVoices()))
|
return list(map(self._voice_to_object, self.speaker.GetVoices()))
|
||||||
|
|
||||||
def _voice_to_object(self, voice: Any):
|
def _voice_to_object(self, voice: Any) -> WindowsVoice:
|
||||||
lang = voice.GetAttribute("language")
|
lang = voice.GetAttribute("language")
|
||||||
lang = lcid_hex_str_to_lang_code(lang)
|
lang = lcid_hex_str_to_lang_code(lang)
|
||||||
name = self._tidy_name(voice.GetAttribute("name"))
|
name = self._tidy_name(voice.GetAttribute("name"))
|
||||||
|
@ -561,7 +561,7 @@ if isWin:
|
||||||
)
|
)
|
||||||
asyncio.run(self.speakText(tag, voice.id))
|
asyncio.run(self.speakText(tag, voice.id))
|
||||||
|
|
||||||
def _on_done(self, ret: Future, cb: OnDoneCallback):
|
def _on_done(self, ret: Future, cb: OnDoneCallback) -> None:
|
||||||
ret.result()
|
ret.result()
|
||||||
|
|
||||||
# inject file into the top of the audio queue
|
# inject file into the top of the audio queue
|
||||||
|
@ -572,7 +572,7 @@ if isWin:
|
||||||
# then tell player to advance, which will cause the file to be played
|
# then tell player to advance, which will cause the file to be played
|
||||||
cb()
|
cb()
|
||||||
|
|
||||||
async def speakText(self, tag: TTSTag, voice_id):
|
async def speakText(self, tag: TTSTag, voice_id) -> None:
|
||||||
import winrt.windows.media.speechsynthesis as speechsynthesis # type: ignore
|
import winrt.windows.media.speechsynthesis as speechsynthesis # type: ignore
|
||||||
import winrt.windows.storage.streams as streams # type: ignore
|
import winrt.windows.storage.streams as streams # type: ignore
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ class LatestVersionFinder(QThread):
|
||||||
self.main = main
|
self.main = main
|
||||||
self.config = main.pm.meta
|
self.config = main.pm.meta
|
||||||
|
|
||||||
def _data(self):
|
def _data(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"ver": versionWithBuild(),
|
"ver": versionWithBuild(),
|
||||||
"os": platDesc(),
|
"os": platDesc(),
|
||||||
|
@ -32,7 +33,7 @@ class LatestVersionFinder(QThread):
|
||||||
"crt": self.config["created"],
|
"crt": self.config["created"],
|
||||||
}
|
}
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
if not self.config["updates"]:
|
if not self.config["updates"]:
|
||||||
return
|
return
|
||||||
d = self._data()
|
d = self._data()
|
||||||
|
@ -55,7 +56,7 @@ class LatestVersionFinder(QThread):
|
||||||
self.clockIsOff.emit(diff) # type: ignore
|
self.clockIsOff.emit(diff) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def askAndUpdate(mw, ver):
|
def askAndUpdate(mw, ver) -> None:
|
||||||
baseStr = tr(TR.QT_MISC_ANKI_UPDATEDANKI_HAS_BEEN_RELEASED, val=ver)
|
baseStr = tr(TR.QT_MISC_ANKI_UPDATEDANKI_HAS_BEEN_RELEASED, val=ver)
|
||||||
msg = QMessageBox(mw)
|
msg = QMessageBox(mw)
|
||||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # type: ignore
|
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # type: ignore
|
||||||
|
@ -72,6 +73,6 @@ def askAndUpdate(mw, ver):
|
||||||
openLink(aqt.appWebsite)
|
openLink(aqt.appWebsite)
|
||||||
|
|
||||||
|
|
||||||
def showMessages(mw, data):
|
def showMessages(mw, data) -> None:
|
||||||
showText(data["msg"], parent=mw, type="html")
|
showText(data["msg"], parent=mw, type="html")
|
||||||
mw.pm.meta["lastMsg"] = data["msgId"]
|
mw.pm.meta["lastMsg"] = data["msgId"]
|
||||||
|
|
|
@ -22,7 +22,7 @@ serverbaseurl = re.compile(r"^.+:\/\/[^\/]+")
|
||||||
|
|
||||||
|
|
||||||
class AnkiWebPage(QWebEnginePage):
|
class AnkiWebPage(QWebEnginePage):
|
||||||
def __init__(self, onBridgeCmd):
|
def __init__(self, onBridgeCmd) -> None:
|
||||||
QWebEnginePage.__init__(self)
|
QWebEnginePage.__init__(self)
|
||||||
self._onBridgeCmd = onBridgeCmd
|
self._onBridgeCmd = onBridgeCmd
|
||||||
self._setupBridge()
|
self._setupBridge()
|
||||||
|
@ -31,7 +31,7 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
def _setupBridge(self) -> None:
|
def _setupBridge(self) -> None:
|
||||||
class Bridge(QObject):
|
class Bridge(QObject):
|
||||||
@pyqtSlot(str, result=str) # type: ignore
|
@pyqtSlot(str, result=str) # type: ignore
|
||||||
def cmd(self, str):
|
def cmd(self, str) -> Any:
|
||||||
return json.dumps(self.onCmd(str))
|
return json.dumps(self.onCmd(str))
|
||||||
|
|
||||||
self._bridge = Bridge()
|
self._bridge = Bridge()
|
||||||
|
@ -74,7 +74,7 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
script.setRunsOnSubFrames(False)
|
script.setRunsOnSubFrames(False)
|
||||||
self.profile().scripts().insert(script)
|
self.profile().scripts().insert(script)
|
||||||
|
|
||||||
def javaScriptConsoleMessage(self, level, msg, line, srcID):
|
def javaScriptConsoleMessage(self, level, msg, line, srcID) -> None:
|
||||||
# not translated because console usually not visible,
|
# not translated because console usually not visible,
|
||||||
# and may only accept ascii text
|
# and may only accept ascii text
|
||||||
if srcID.startswith("data"):
|
if srcID.startswith("data"):
|
||||||
|
@ -101,7 +101,7 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
# https://github.com/ankitects/anki/pull/560
|
# https://github.com/ankitects/anki/pull/560
|
||||||
sys.stdout.write(buf)
|
sys.stdout.write(buf)
|
||||||
|
|
||||||
def acceptNavigationRequest(self, url, navType, isMainFrame):
|
def acceptNavigationRequest(self, url, navType, isMainFrame) -> bool:
|
||||||
if not self.open_links_externally:
|
if not self.open_links_externally:
|
||||||
return super().acceptNavigationRequest(url, navType, isMainFrame)
|
return super().acceptNavigationRequest(url, navType, isMainFrame)
|
||||||
|
|
||||||
|
@ -120,10 +120,10 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
openLink(url)
|
openLink(url)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _onCmd(self, str):
|
def _onCmd(self, str) -> None:
|
||||||
return self._onBridgeCmd(str)
|
return self._onBridgeCmd(str)
|
||||||
|
|
||||||
def javaScriptAlert(self, url: QUrl, text: str):
|
def javaScriptAlert(self, url: QUrl, text: str) -> None:
|
||||||
showInfo(text)
|
showInfo(text)
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ class WebContent:
|
||||||
You should avoid overwriting or interfering with existing data as much
|
You should avoid overwriting or interfering with existing data as much
|
||||||
as possible, instead opting to append your own changes, e.g.:
|
as possible, instead opting to append your own changes, e.g.:
|
||||||
|
|
||||||
def on_webview_will_set_content(web_content: WebContent, context):
|
def on_webview_will_set_content(web_content: WebContent, context) -> None:
|
||||||
web_content.body += "<my_html>"
|
web_content.body += "<my_html>"
|
||||||
web_content.head += "<my_head>"
|
web_content.head += "<my_head>"
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ class WebContent:
|
||||||
Then append the subpaths to the corresponding web_content fields
|
Then append the subpaths to the corresponding web_content fields
|
||||||
within a function subscribing to gui_hooks.webview_will_set_content:
|
within a function subscribing to gui_hooks.webview_will_set_content:
|
||||||
|
|
||||||
def on_webview_will_set_content(web_content: WebContent, context):
|
def on_webview_will_set_content(web_content: WebContent, context) -> None:
|
||||||
addon_package = mw.addonManager.addonFromModule(__name__)
|
addon_package = mw.addonManager.addonFromModule(__name__)
|
||||||
web_content.css.append(
|
web_content.css.append(
|
||||||
f"/_addons/{addon_package}/web/my-addon.css")
|
f"/_addons/{addon_package}/web/my-addon.css")
|
||||||
|
@ -251,7 +251,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
def set_open_links_externally(self, enable: bool) -> None:
|
def set_open_links_externally(self, enable: bool) -> None:
|
||||||
self._page.open_links_externally = enable
|
self._page.open_links_externally = enable
|
||||||
|
|
||||||
def onEsc(self):
|
def onEsc(self) -> None:
|
||||||
w = self.parent()
|
w = self.parent()
|
||||||
while w:
|
while w:
|
||||||
if isinstance(w, QDialog) or isinstance(w, QMainWindow):
|
if isinstance(w, QDialog) or isinstance(w, QMainWindow):
|
||||||
|
@ -266,7 +266,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
break
|
break
|
||||||
w = w.parent()
|
w = w.parent()
|
||||||
|
|
||||||
def onCopy(self):
|
def onCopy(self) -> None:
|
||||||
if not self.selectedText():
|
if not self.selectedText():
|
||||||
ctx = self._page.contextMenuData()
|
ctx = self._page.contextMenuData()
|
||||||
if ctx and ctx.mediaType() == QWebEngineContextMenuData.MediaTypeImage:
|
if ctx and ctx.mediaType() == QWebEngineContextMenuData.MediaTypeImage:
|
||||||
|
@ -274,16 +274,16 @@ class AnkiWebView(QWebEngineView):
|
||||||
else:
|
else:
|
||||||
self.triggerPageAction(QWebEnginePage.Copy)
|
self.triggerPageAction(QWebEnginePage.Copy)
|
||||||
|
|
||||||
def onCut(self):
|
def onCut(self) -> None:
|
||||||
self.triggerPageAction(QWebEnginePage.Cut)
|
self.triggerPageAction(QWebEnginePage.Cut)
|
||||||
|
|
||||||
def onPaste(self):
|
def onPaste(self) -> None:
|
||||||
self.triggerPageAction(QWebEnginePage.Paste)
|
self.triggerPageAction(QWebEnginePage.Paste)
|
||||||
|
|
||||||
def onMiddleClickPaste(self):
|
def onMiddleClickPaste(self) -> None:
|
||||||
self.triggerPageAction(QWebEnginePage.Paste)
|
self.triggerPageAction(QWebEnginePage.Paste)
|
||||||
|
|
||||||
def onSelectAll(self):
|
def onSelectAll(self) -> None:
|
||||||
self.triggerPageAction(QWebEnginePage.SelectAll)
|
self.triggerPageAction(QWebEnginePage.SelectAll)
|
||||||
|
|
||||||
def contextMenuEvent(self, evt: QContextMenuEvent) -> None:
|
def contextMenuEvent(self, evt: QContextMenuEvent) -> None:
|
||||||
|
@ -293,7 +293,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
gui_hooks.webview_will_show_context_menu(self, m)
|
gui_hooks.webview_will_show_context_menu(self, m)
|
||||||
m.popup(QCursor.pos())
|
m.popup(QCursor.pos())
|
||||||
|
|
||||||
def dropEvent(self, evt):
|
def dropEvent(self, evt) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def setHtml(self, html: str) -> None: # type: ignore
|
def setHtml(self, html: str) -> None: # type: ignore
|
||||||
|
@ -312,7 +312,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
if oldFocus:
|
if oldFocus:
|
||||||
oldFocus.setFocus()
|
oldFocus.setFocus()
|
||||||
|
|
||||||
def load(self, url: QUrl):
|
def load(self, url: QUrl) -> None:
|
||||||
# allow queuing actions when loading url directly
|
# allow queuing actions when loading url directly
|
||||||
self._domDone = False
|
self._domDone = False
|
||||||
super().load(url)
|
super().load(url)
|
||||||
|
@ -364,7 +364,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
else:
|
else:
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
def _getWindowColor(self):
|
def _getWindowColor(self) -> QColor:
|
||||||
if theme_manager.night_mode:
|
if theme_manager.night_mode:
|
||||||
return theme_manager.qcolor("window-bg")
|
return theme_manager.qcolor("window-bg")
|
||||||
if isMac:
|
if isMac:
|
||||||
|
@ -508,7 +508,7 @@ body {{ zoom: {zoom}; background: {background}; direction: {lang_dir}; {font} }}
|
||||||
def _evalWithCallback(self, js: str, cb: Callable[[Any], Any]) -> None:
|
def _evalWithCallback(self, js: str, cb: Callable[[Any], Any]) -> None:
|
||||||
if cb:
|
if cb:
|
||||||
|
|
||||||
def handler(val):
|
def handler(val) -> None:
|
||||||
if self._shouldIgnoreWebEvent():
|
if self._shouldIgnoreWebEvent():
|
||||||
print("ignored late js callback", cb)
|
print("ignored late js callback", cb)
|
||||||
return
|
return
|
||||||
|
@ -597,18 +597,18 @@ body {{ zoom: {zoom}; background: {background}; direction: {lang_dir}; {font} }}
|
||||||
self.onBridgeCmd = func
|
self.onBridgeCmd = func
|
||||||
self._bridge_context = context
|
self._bridge_context = context
|
||||||
|
|
||||||
def hide_while_preserving_layout(self):
|
def hide_while_preserving_layout(self) -> None:
|
||||||
"Hide but keep existing size."
|
"Hide but keep existing size."
|
||||||
sp = self.sizePolicy()
|
sp = self.sizePolicy()
|
||||||
sp.setRetainSizeWhenHidden(True)
|
sp.setRetainSizeWhenHidden(True)
|
||||||
self.setSizePolicy(sp)
|
self.setSizePolicy(sp)
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
def inject_dynamic_style_and_show(self):
|
def inject_dynamic_style_and_show(self) -> None:
|
||||||
"Add dynamic styling, and reveal."
|
"Add dynamic styling, and reveal."
|
||||||
css = self.standard_css()
|
css = self.standard_css()
|
||||||
|
|
||||||
def after_style(arg):
|
def after_style(arg) -> None:
|
||||||
gui_hooks.webview_did_inject_style_into_page(self)
|
gui_hooks.webview_did_inject_style_into_page(self)
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,5 @@
|
||||||
|
|
||||||
(sleep 1 && touch aqt)
|
(sleep 1 && touch aqt)
|
||||||
. ~/pyenv/bin/activate
|
. ~/pyenv/bin/activate
|
||||||
fswatch -o aqt | xargs -n1 -I{} sh -c 'printf \\033c; dmypy run aqt'
|
fswatch -o aqt | xargs -n1 -I{} sh -c 'printf \\033c\\n; dmypy run aqt'
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue