mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 22:42:25 -04:00
add types to various other files
Mainly automated with MonkeyType
This commit is contained in:
parent
84f8d7f604
commit
f15715fb07
25 changed files with 227 additions and 182 deletions
|
@ -137,7 +137,7 @@ class AddCards(QDialog):
|
||||||
def removeTempNote(self, note: Note) -> None:
|
def removeTempNote(self, note: Note) -> None:
|
||||||
print("removeTempNote() will go away")
|
print("removeTempNote() will go away")
|
||||||
|
|
||||||
def addHistory(self, note):
|
def addHistory(self, note: Note) -> None:
|
||||||
self.history.insert(0, note.id)
|
self.history.insert(0, note.id)
|
||||||
self.history = self.history[:15]
|
self.history = self.history[:15]
|
||||||
self.historyButton.setEnabled(True)
|
self.historyButton.setEnabled(True)
|
||||||
|
@ -186,10 +186,10 @@ class AddCards(QDialog):
|
||||||
gui_hooks.add_cards_did_add_note(note)
|
gui_hooks.add_cards_did_add_note(note)
|
||||||
return note
|
return note
|
||||||
|
|
||||||
def addCards(self):
|
def addCards(self) -> None:
|
||||||
self.editor.saveNow(self._addCards)
|
self.editor.saveNow(self._addCards)
|
||||||
|
|
||||||
def _addCards(self):
|
def _addCards(self) -> None:
|
||||||
self.editor.saveAddModeVars()
|
self.editor.saveAddModeVars()
|
||||||
if not self.addNote(self.editor.note):
|
if not self.addNote(self.editor.note):
|
||||||
return
|
return
|
||||||
|
@ -202,7 +202,7 @@ class AddCards(QDialog):
|
||||||
self.onReset(keep=True)
|
self.onReset(keep=True)
|
||||||
self.mw.col.autosave()
|
self.mw.col.autosave()
|
||||||
|
|
||||||
def keyPressEvent(self, evt):
|
def keyPressEvent(self, evt: QKeyEvent) -> None:
|
||||||
"Show answer on RET or register answer."
|
"Show answer on RET or register answer."
|
||||||
if evt.key() in (Qt.Key_Enter, Qt.Key_Return) and self.editor.tags.hasFocus():
|
if evt.key() in (Qt.Key_Enter, Qt.Key_Return) and self.editor.tags.hasFocus():
|
||||||
evt.accept()
|
evt.accept()
|
||||||
|
|
|
@ -14,6 +14,7 @@ from anki.lang import without_unicode_isolation
|
||||||
from anki.notes import Note
|
from anki.notes import Note
|
||||||
from anki.template import TemplateRenderContext
|
from anki.template import TemplateRenderContext
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
|
from aqt.forms.browserdisp import Ui_Dialog
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.schema_change_tracker import ChangeTracker
|
from aqt.schema_change_tracker import ChangeTracker
|
||||||
from aqt.sound import av_player, play_clicked_audio
|
from aqt.sound import av_player, play_clicked_audio
|
||||||
|
@ -90,7 +91,7 @@ class CardLayout(QDialog):
|
||||||
# as users tend to accidentally type into the template
|
# as users tend to accidentally type into the template
|
||||||
self.setFocus()
|
self.setFocus()
|
||||||
|
|
||||||
def redraw_everything(self):
|
def redraw_everything(self) -> None:
|
||||||
self.ignore_change_signals = True
|
self.ignore_change_signals = True
|
||||||
self.updateTopArea()
|
self.updateTopArea()
|
||||||
self.ignore_change_signals = False
|
self.ignore_change_signals = False
|
||||||
|
@ -104,13 +105,13 @@ class CardLayout(QDialog):
|
||||||
self.fill_fields_from_template()
|
self.fill_fields_from_template()
|
||||||
self.renderPreview()
|
self.renderPreview()
|
||||||
|
|
||||||
def _isCloze(self):
|
def _isCloze(self) -> bool:
|
||||||
return self.model["type"] == MODEL_CLOZE
|
return self.model["type"] == MODEL_CLOZE
|
||||||
|
|
||||||
# Top area
|
# Top area
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def setupTopArea(self):
|
def setupTopArea(self) -> None:
|
||||||
self.topArea = QWidget()
|
self.topArea = QWidget()
|
||||||
self.topArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
self.topArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||||
self.topAreaForm = aqt.forms.clayout_top.Ui_Form()
|
self.topAreaForm = aqt.forms.clayout_top.Ui_Form()
|
||||||
|
@ -125,10 +126,10 @@ class CardLayout(QDialog):
|
||||||
)
|
)
|
||||||
self.topAreaForm.card_type_label.setText(tr(TR.CARD_TEMPLATES_CARD_TYPE))
|
self.topAreaForm.card_type_label.setText(tr(TR.CARD_TEMPLATES_CARD_TYPE))
|
||||||
|
|
||||||
def updateTopArea(self):
|
def updateTopArea(self) -> None:
|
||||||
self.updateCardNames()
|
self.updateCardNames()
|
||||||
|
|
||||||
def updateCardNames(self):
|
def updateCardNames(self) -> None:
|
||||||
self.ignore_change_signals = True
|
self.ignore_change_signals = True
|
||||||
combo = self.topAreaForm.templatesBox
|
combo = self.topAreaForm.templatesBox
|
||||||
combo.clear()
|
combo.clear()
|
||||||
|
@ -170,7 +171,7 @@ class CardLayout(QDialog):
|
||||||
s += "+..."
|
s += "+..."
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def setupShortcuts(self):
|
def setupShortcuts(self) -> None:
|
||||||
self.tform.front_button.setToolTip(shortcut("Ctrl+1"))
|
self.tform.front_button.setToolTip(shortcut("Ctrl+1"))
|
||||||
self.tform.back_button.setToolTip(shortcut("Ctrl+2"))
|
self.tform.back_button.setToolTip(shortcut("Ctrl+2"))
|
||||||
self.tform.style_button.setToolTip(shortcut("Ctrl+3"))
|
self.tform.style_button.setToolTip(shortcut("Ctrl+3"))
|
||||||
|
@ -193,7 +194,7 @@ class CardLayout(QDialog):
|
||||||
# Main area setup
|
# Main area setup
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def setupMainArea(self):
|
def setupMainArea(self) -> None:
|
||||||
split = self.mainArea = QSplitter()
|
split = self.mainArea = QSplitter()
|
||||||
split.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
split.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
split.setOrientation(Qt.Horizontal)
|
split.setOrientation(Qt.Horizontal)
|
||||||
|
@ -216,7 +217,7 @@ class CardLayout(QDialog):
|
||||||
split.addWidget(right)
|
split.addWidget(right)
|
||||||
split.setCollapsible(1, False)
|
split.setCollapsible(1, False)
|
||||||
|
|
||||||
def setup_edit_area(self):
|
def setup_edit_area(self) -> None:
|
||||||
tform = self.tform
|
tform = self.tform
|
||||||
|
|
||||||
tform.front_button.setText(tr(TR.CARD_TEMPLATES_FRONT_TEMPLATE))
|
tform.front_button.setText(tr(TR.CARD_TEMPLATES_FRONT_TEMPLATE))
|
||||||
|
@ -248,7 +249,7 @@ class CardLayout(QDialog):
|
||||||
qconnect(widg.textChanged, self.on_search_changed)
|
qconnect(widg.textChanged, self.on_search_changed)
|
||||||
qconnect(widg.returnPressed, self.on_search_next)
|
qconnect(widg.returnPressed, self.on_search_next)
|
||||||
|
|
||||||
def setup_cloze_number_box(self):
|
def setup_cloze_number_box(self) -> None:
|
||||||
names = (tr(TR.CARD_TEMPLATES_CLOZE, val=n) for n in self.cloze_numbers)
|
names = (tr(TR.CARD_TEMPLATES_CLOZE, val=n) for n in self.cloze_numbers)
|
||||||
self.pform.cloze_number_combo.addItems(names)
|
self.pform.cloze_number_combo.addItems(names)
|
||||||
try:
|
try:
|
||||||
|
@ -266,7 +267,7 @@ class CardLayout(QDialog):
|
||||||
self.have_autoplayed = False
|
self.have_autoplayed = False
|
||||||
self._renderPreview()
|
self._renderPreview()
|
||||||
|
|
||||||
def on_editor_toggled(self):
|
def on_editor_toggled(self) -> None:
|
||||||
if self.tform.front_button.isChecked():
|
if self.tform.front_button.isChecked():
|
||||||
self.current_editor_index = 0
|
self.current_editor_index = 0
|
||||||
self.pform.preview_front.setChecked(True)
|
self.pform.preview_front.setChecked(True)
|
||||||
|
@ -297,7 +298,7 @@ class CardLayout(QDialog):
|
||||||
text = self.tform.search_edit.text()
|
text = self.tform.search_edit.text()
|
||||||
self.on_search_changed(text)
|
self.on_search_changed(text)
|
||||||
|
|
||||||
def setup_preview(self):
|
def setup_preview(self) -> None:
|
||||||
pform = self.pform
|
pform = self.pform
|
||||||
self.preview_web = AnkiWebView(title="card layout")
|
self.preview_web = AnkiWebView(title="card layout")
|
||||||
pform.verticalLayout.addWidget(self.preview_web)
|
pform.verticalLayout.addWidget(self.preview_web)
|
||||||
|
@ -336,7 +337,7 @@ class CardLayout(QDialog):
|
||||||
self.cloze_numbers = []
|
self.cloze_numbers = []
|
||||||
self.pform.cloze_number_combo.setHidden(True)
|
self.pform.cloze_number_combo.setHidden(True)
|
||||||
|
|
||||||
def on_fill_empty_action_toggled(self):
|
def on_fill_empty_action_toggled(self) -> None:
|
||||||
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()
|
||||||
|
|
||||||
|
@ -344,11 +345,11 @@ class CardLayout(QDialog):
|
||||||
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()
|
||||||
|
|
||||||
def on_mobile_class_action_toggled(self):
|
def on_mobile_class_action_toggled(self) -> None:
|
||||||
self.mobile_emulation_enabled = not self.mobile_emulation_enabled
|
self.mobile_emulation_enabled = not self.mobile_emulation_enabled
|
||||||
self.on_preview_toggled()
|
self.on_preview_toggled()
|
||||||
|
|
||||||
def on_preview_settings(self):
|
def on_preview_settings(self) -> None:
|
||||||
m = QMenu(self)
|
m = QMenu(self)
|
||||||
|
|
||||||
a = m.addAction(tr(TR.CARD_TEMPLATES_FILL_EMPTY))
|
a = m.addAction(tr(TR.CARD_TEMPLATES_FILL_EMPTY))
|
||||||
|
@ -370,7 +371,7 @@ class CardLayout(QDialog):
|
||||||
|
|
||||||
m.exec_(self.pform.preview_settings.mapToGlobal(QPoint(0, 0)))
|
m.exec_(self.pform.preview_settings.mapToGlobal(QPoint(0, 0)))
|
||||||
|
|
||||||
def on_preview_toggled(self):
|
def on_preview_toggled(self) -> None:
|
||||||
self.have_autoplayed = False
|
self.have_autoplayed = False
|
||||||
self._renderPreview()
|
self._renderPreview()
|
||||||
|
|
||||||
|
@ -388,7 +389,7 @@ class CardLayout(QDialog):
|
||||||
# Buttons
|
# Buttons
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def setupButtons(self):
|
def setupButtons(self) -> None:
|
||||||
l = self.buttons = QHBoxLayout()
|
l = self.buttons = QHBoxLayout()
|
||||||
help = QPushButton(tr(TR.ACTIONS_HELP))
|
help = QPushButton(tr(TR.ACTIONS_HELP))
|
||||||
help.setAutoDefault(False)
|
help.setAutoDefault(False)
|
||||||
|
@ -424,7 +425,7 @@ class CardLayout(QDialog):
|
||||||
return self.templates[0]
|
return self.templates[0]
|
||||||
return self.templates[self.ord]
|
return self.templates[self.ord]
|
||||||
|
|
||||||
def fill_fields_from_template(self):
|
def fill_fields_from_template(self) -> None:
|
||||||
t = self.current_template()
|
t = self.current_template()
|
||||||
self.ignore_change_signals = True
|
self.ignore_change_signals = True
|
||||||
|
|
||||||
|
@ -438,7 +439,7 @@ class CardLayout(QDialog):
|
||||||
self.tform.edit_area.setPlainText(text)
|
self.tform.edit_area.setPlainText(text)
|
||||||
self.ignore_change_signals = False
|
self.ignore_change_signals = False
|
||||||
|
|
||||||
def write_edits_to_template_and_redraw(self):
|
def write_edits_to_template_and_redraw(self) -> None:
|
||||||
if self.ignore_change_signals:
|
if self.ignore_change_signals:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -458,14 +459,14 @@ class CardLayout(QDialog):
|
||||||
# Preview
|
# Preview
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
_previewTimer = None
|
_previewTimer: Optional[QTimer] = None
|
||||||
|
|
||||||
def renderPreview(self):
|
def renderPreview(self) -> None:
|
||||||
# schedule a preview when timing stops
|
# schedule a preview when timing stops
|
||||||
self.cancelPreviewTimer()
|
self.cancelPreviewTimer()
|
||||||
self._previewTimer = self.mw.progress.timer(200, self._renderPreview, False)
|
self._previewTimer = self.mw.progress.timer(200, self._renderPreview, False)
|
||||||
|
|
||||||
def cancelPreviewTimer(self):
|
def cancelPreviewTimer(self) -> None:
|
||||||
if self._previewTimer:
|
if self._previewTimer:
|
||||||
self._previewTimer.stop()
|
self._previewTimer.stop()
|
||||||
self._previewTimer = None
|
self._previewTimer = None
|
||||||
|
@ -512,7 +513,7 @@ class CardLayout(QDialog):
|
||||||
|
|
||||||
self.updateCardNames()
|
self.updateCardNames()
|
||||||
|
|
||||||
def maybeTextInput(self, txt, type="q"):
|
def maybeTextInput(self, txt: str, type: str = "q") -> str:
|
||||||
if "[[type:" not in txt:
|
if "[[type:" not in txt:
|
||||||
return txt
|
return txt
|
||||||
origLen = len(txt)
|
origLen = len(txt)
|
||||||
|
@ -668,7 +669,7 @@ class CardLayout(QDialog):
|
||||||
dst["qfmt"] = m.group(2).strip()
|
dst["qfmt"] = m.group(2).strip()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def onMore(self):
|
def onMore(self) -> None:
|
||||||
m = QMenu(self)
|
m = QMenu(self)
|
||||||
|
|
||||||
if not self._isCloze():
|
if not self._isCloze():
|
||||||
|
@ -699,7 +700,7 @@ class CardLayout(QDialog):
|
||||||
|
|
||||||
m.exec_(self.topAreaForm.templateOptions.mapToGlobal(QPoint(0, 0)))
|
m.exec_(self.topAreaForm.templateOptions.mapToGlobal(QPoint(0, 0)))
|
||||||
|
|
||||||
def onBrowserDisplay(self):
|
def onBrowserDisplay(self) -> None:
|
||||||
d = QDialog()
|
d = QDialog()
|
||||||
disable_help_button(d)
|
disable_help_button(d)
|
||||||
f = aqt.forms.browserdisp.Ui_Dialog()
|
f = aqt.forms.browserdisp.Ui_Dialog()
|
||||||
|
@ -714,7 +715,7 @@ class CardLayout(QDialog):
|
||||||
qconnect(f.buttonBox.accepted, lambda: self.onBrowserDisplayOk(f))
|
qconnect(f.buttonBox.accepted, lambda: self.onBrowserDisplayOk(f))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
def onBrowserDisplayOk(self, f):
|
def onBrowserDisplayOk(self, f: Ui_Dialog) -> None:
|
||||||
t = self.current_template()
|
t = self.current_template()
|
||||||
self.change_tracker.mark_basic()
|
self.change_tracker.mark_basic()
|
||||||
t["bqfmt"] = f.qfmt.text().strip()
|
t["bqfmt"] = f.qfmt.text().strip()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# -*- 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
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import SearchTerm
|
from anki.collection import SearchTerm
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
|
@ -35,7 +36,7 @@ class CustomStudy(QDialog):
|
||||||
f.radioNew.click()
|
f.radioNew.click()
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
def setupSignals(self):
|
def setupSignals(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
qconnect(f.radioNew.clicked, lambda: self.onRadioChange(RADIO_NEW))
|
qconnect(f.radioNew.clicked, lambda: self.onRadioChange(RADIO_NEW))
|
||||||
qconnect(f.radioRev.clicked, lambda: self.onRadioChange(RADIO_REV))
|
qconnect(f.radioRev.clicked, lambda: self.onRadioChange(RADIO_REV))
|
||||||
|
@ -44,7 +45,7 @@ class CustomStudy(QDialog):
|
||||||
qconnect(f.radioPreview.clicked, lambda: self.onRadioChange(RADIO_PREVIEW))
|
qconnect(f.radioPreview.clicked, lambda: self.onRadioChange(RADIO_PREVIEW))
|
||||||
qconnect(f.radioCram.clicked, lambda: self.onRadioChange(RADIO_CRAM))
|
qconnect(f.radioCram.clicked, lambda: self.onRadioChange(RADIO_CRAM))
|
||||||
|
|
||||||
def onRadioChange(self, idx):
|
def onRadioChange(self, idx: int) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
sp = f.spin
|
sp = f.spin
|
||||||
smin = 1
|
smin = 1
|
||||||
|
@ -123,7 +124,7 @@ class CustomStudy(QDialog):
|
||||||
f.buttonBox.button(QDialogButtonBox.Ok).setText(ok)
|
f.buttonBox.button(QDialogButtonBox.Ok).setText(ok)
|
||||||
self.radioIdx = idx
|
self.radioIdx = idx
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
i = self.radioIdx
|
i = self.radioIdx
|
||||||
spin = f.spin.value()
|
spin = f.spin.value()
|
||||||
|
@ -132,13 +133,15 @@ class CustomStudy(QDialog):
|
||||||
self.mw.col.decks.save(self.deck)
|
self.mw.col.decks.save(self.deck)
|
||||||
self.mw.col.sched.extendLimits(spin, 0)
|
self.mw.col.sched.extendLimits(spin, 0)
|
||||||
self.mw.reset()
|
self.mw.reset()
|
||||||
return QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
return
|
||||||
elif i == RADIO_REV:
|
elif i == RADIO_REV:
|
||||||
self.deck["extendRev"] = spin
|
self.deck["extendRev"] = spin
|
||||||
self.mw.col.decks.save(self.deck)
|
self.mw.col.decks.save(self.deck)
|
||||||
self.mw.col.sched.extendLimits(0, spin)
|
self.mw.col.sched.extendLimits(0, spin)
|
||||||
self.mw.reset()
|
self.mw.reset()
|
||||||
return QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
return
|
||||||
elif i == RADIO_CRAM:
|
elif i == RADIO_CRAM:
|
||||||
tags = self._getTags()
|
tags = self._getTags()
|
||||||
# the rest create a filtered deck
|
# the rest create a filtered deck
|
||||||
|
@ -146,7 +149,8 @@ class CustomStudy(QDialog):
|
||||||
if cur:
|
if cur:
|
||||||
if not cur["dyn"]:
|
if not cur["dyn"]:
|
||||||
showInfo(tr(TR.CUSTOM_STUDY_MUST_RENAME_DECK))
|
showInfo(tr(TR.CUSTOM_STUDY_MUST_RENAME_DECK))
|
||||||
return QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
# safe to empty
|
# safe to empty
|
||||||
self.mw.col.sched.empty_filtered_deck(cur["id"])
|
self.mw.col.sched.empty_filtered_deck(cur["id"])
|
||||||
|
@ -211,7 +215,8 @@ class CustomStudy(QDialog):
|
||||||
# generate cards
|
# generate cards
|
||||||
self.created_custom_study = True
|
self.created_custom_study = True
|
||||||
if not self.mw.col.sched.rebuild_filtered_deck(dyn["id"]):
|
if not self.mw.col.sched.rebuild_filtered_deck(dyn["id"]):
|
||||||
return showWarning(tr(TR.CUSTOM_STUDY_NO_CARDS_MATCHED_THE_CRITERIA_YOU))
|
showWarning(tr(TR.CUSTOM_STUDY_NO_CARDS_MATCHED_THE_CRITERIA_YOU))
|
||||||
|
return
|
||||||
self.mw.moveToState("overview")
|
self.mw.moveToState("overview")
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
||||||
|
@ -222,7 +227,7 @@ class CustomStudy(QDialog):
|
||||||
# fixme: clean up the empty custom study deck
|
# fixme: clean up the empty custom study deck
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def _getTags(self):
|
def _getTags(self) -> str:
|
||||||
from aqt.taglimit import TagLimit
|
from aqt.taglimit import TagLimit
|
||||||
|
|
||||||
return TagLimit(self.mw, self).tags
|
return TagLimit(self.mw, self).tags
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# -*- 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 typing import List, Optional
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import SearchTerm
|
from anki.collection import SearchTerm
|
||||||
from anki.errors import InvalidInput
|
from anki.errors import InvalidInput
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
|
from aqt.main import AnkiQt
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
TR,
|
TR,
|
||||||
|
@ -23,7 +24,13 @@ from aqt.utils import (
|
||||||
|
|
||||||
|
|
||||||
class DeckConf(QDialog):
|
class DeckConf(QDialog):
|
||||||
def __init__(self, mw, first=False, search="", deck=None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
mw: AnkiQt,
|
||||||
|
first: bool = False,
|
||||||
|
search: str = "",
|
||||||
|
deck: Optional[Dict] = None,
|
||||||
|
) -> None:
|
||||||
QDialog.__init__(self, mw)
|
QDialog.__init__(self, mw)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.deck = deck or self.mw.col.decks.current()
|
self.deck = deck or self.mw.col.decks.current()
|
||||||
|
@ -65,7 +72,7 @@ class DeckConf(QDialog):
|
||||||
self.exec_()
|
self.exec_()
|
||||||
saveGeom(self, "dyndeckconf")
|
saveGeom(self, "dyndeckconf")
|
||||||
|
|
||||||
def initialSetup(self):
|
def initialSetup(self) -> None:
|
||||||
import anki.consts as cs
|
import anki.consts as cs
|
||||||
|
|
||||||
self.form.order.addItems(list(cs.dynOrderLabels(self.mw.col).values()))
|
self.form.order.addItems(list(cs.dynOrderLabels(self.mw.col).values()))
|
||||||
|
@ -73,12 +80,12 @@ class DeckConf(QDialog):
|
||||||
|
|
||||||
qconnect(self.form.resched.stateChanged, self._onReschedToggled)
|
qconnect(self.form.resched.stateChanged, self._onReschedToggled)
|
||||||
|
|
||||||
def _onReschedToggled(self, _state):
|
def _onReschedToggled(self, _state: int) -> None:
|
||||||
self.form.previewDelayWidget.setVisible(
|
self.form.previewDelayWidget.setVisible(
|
||||||
not self.form.resched.isChecked() and self.mw.col.schedVer() > 1
|
not self.form.resched.isChecked() and self.mw.col.schedVer() > 1
|
||||||
)
|
)
|
||||||
|
|
||||||
def loadConf(self):
|
def loadConf(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
d = self.deck
|
d = self.deck
|
||||||
|
|
||||||
|
@ -113,7 +120,7 @@ class DeckConf(QDialog):
|
||||||
f.secondFilter.setChecked(False)
|
f.secondFilter.setChecked(False)
|
||||||
f.filter2group.setVisible(False)
|
f.filter2group.setVisible(False)
|
||||||
|
|
||||||
def saveConf(self):
|
def saveConf(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
d = self.deck
|
d = self.deck
|
||||||
d["resched"] = f.resched.isChecked()
|
d["resched"] = f.resched.isChecked()
|
||||||
|
@ -142,7 +149,7 @@ class DeckConf(QDialog):
|
||||||
self.ok = False
|
self.ok = False
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.saveConf()
|
self.saveConf()
|
||||||
except InvalidInput as err:
|
except InvalidInput as err:
|
||||||
|
|
|
@ -52,10 +52,10 @@ class EditCurrent(QDialog):
|
||||||
tooltip("Please finish editing the existing card first.")
|
tooltip("Please finish editing the existing card first.")
|
||||||
self.onReset()
|
self.onReset()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.saveAndClose()
|
self.saveAndClose()
|
||||||
|
|
||||||
def saveAndClose(self):
|
def saveAndClose(self) -> None:
|
||||||
self.editor.saveNow(self._saveAndClose)
|
self.editor.saveNow(self._saveAndClose)
|
||||||
|
|
||||||
def _saveAndClose(self) -> None:
|
def _saveAndClose(self) -> None:
|
||||||
|
|
|
@ -68,7 +68,7 @@ class EmptyCardsDialog(QDialog):
|
||||||
def _on_note_link_clicked(self, link):
|
def _on_note_link_clicked(self, link):
|
||||||
self.mw.browser_search(link)
|
self.mw.browser_search(link)
|
||||||
|
|
||||||
def _on_delete(self):
|
def _on_delete(self) -> None:
|
||||||
self.mw.progress.start()
|
self.mw.progress.start()
|
||||||
|
|
||||||
def delete():
|
def delete():
|
||||||
|
|
|
@ -5,10 +5,12 @@ import html
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from markdown import markdown
|
from markdown import markdown
|
||||||
|
|
||||||
from aqt import mw
|
from aqt import mw
|
||||||
|
from aqt.main import AnkiQt
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import TR, showText, showWarning, supportText, tr
|
from aqt.utils import TR, showText, showWarning, supportText, tr
|
||||||
|
|
||||||
|
@ -29,20 +31,20 @@ class ErrorHandler(QObject):
|
||||||
|
|
||||||
errorTimer = pyqtSignal()
|
errorTimer = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, mw):
|
def __init__(self, mw: AnkiQt) -> None:
|
||||||
QObject.__init__(self, mw)
|
QObject.__init__(self, mw)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.timer = None
|
self.timer: Optional[QTimer] = None
|
||||||
qconnect(self.errorTimer, self._setTimer)
|
qconnect(self.errorTimer, self._setTimer)
|
||||||
self.pool = ""
|
self.pool = ""
|
||||||
self._oldstderr = sys.stderr
|
self._oldstderr = sys.stderr
|
||||||
sys.stderr = self
|
sys.stderr = self
|
||||||
|
|
||||||
def unload(self):
|
def unload(self) -> None:
|
||||||
sys.stderr = self._oldstderr
|
sys.stderr = self._oldstderr
|
||||||
sys.excepthook = None
|
sys.excepthook = None
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data: str) -> None:
|
||||||
# dump to stdout
|
# dump to stdout
|
||||||
sys.stdout.write(data)
|
sys.stdout.write(data)
|
||||||
# save in buffer
|
# save in buffer
|
||||||
|
@ -50,12 +52,12 @@ class ErrorHandler(QObject):
|
||||||
# and update timer
|
# and update timer
|
||||||
self.setTimer()
|
self.setTimer()
|
||||||
|
|
||||||
def setTimer(self):
|
def setTimer(self) -> None:
|
||||||
# we can't create a timer from a different thread, so we post a
|
# we can't create a timer from a different thread, so we post a
|
||||||
# message to the object on the main thread
|
# message to the object on the main thread
|
||||||
self.errorTimer.emit() # type: ignore
|
self.errorTimer.emit() # type: ignore
|
||||||
|
|
||||||
def _setTimer(self):
|
def _setTimer(self) -> None:
|
||||||
if not self.timer:
|
if not self.timer:
|
||||||
self.timer = QTimer(self.mw)
|
self.timer = QTimer(self.mw)
|
||||||
qconnect(self.timer.timeout, self.onTimeout)
|
qconnect(self.timer.timeout, self.onTimeout)
|
||||||
|
@ -66,7 +68,7 @@ class ErrorHandler(QObject):
|
||||||
def tempFolderMsg(self):
|
def tempFolderMsg(self):
|
||||||
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):
|
def onTimeout(self) -> None:
|
||||||
error = html.escape(self.pool)
|
error = html.escape(self.pool)
|
||||||
self.pool = ""
|
self.pool = ""
|
||||||
self.mw.progress.clear()
|
self.mw.progress.clear()
|
||||||
|
@ -75,15 +77,19 @@ class ErrorHandler(QObject):
|
||||||
if "DeprecationWarning" in error:
|
if "DeprecationWarning" in error:
|
||||||
return
|
return
|
||||||
if "10013" in error:
|
if "10013" in error:
|
||||||
return showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS))
|
showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS))
|
||||||
|
return
|
||||||
if "no default input" in error.lower():
|
if "no default input" in error.lower():
|
||||||
return showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE))
|
showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE))
|
||||||
|
return
|
||||||
if "invalidTempFolder" in error:
|
if "invalidTempFolder" in error:
|
||||||
return showWarning(self.tempFolderMsg())
|
showWarning(self.tempFolderMsg())
|
||||||
|
return
|
||||||
if "Beautiful Soup is not an HTTP client" in error:
|
if "Beautiful Soup is not an HTTP client" in error:
|
||||||
return
|
return
|
||||||
if "database or disk is full" in error or "Errno 28" in error:
|
if "database or disk is full" in error or "Errno 28" in error:
|
||||||
return showWarning(tr(TR.QT_MISC_YOUR_COMPUTERS_STORAGE_MAY_BE_FULL))
|
showWarning(tr(TR.QT_MISC_YOUR_COMPUTERS_STORAGE_MAY_BE_FULL))
|
||||||
|
return
|
||||||
if "disk I/O error" in error:
|
if "disk I/O error" in error:
|
||||||
showWarning(markdown(tr(TR.ERRORS_ACCESSING_DB)))
|
showWarning(markdown(tr(TR.ERRORS_ACCESSING_DB)))
|
||||||
return
|
return
|
||||||
|
|
|
@ -71,7 +71,7 @@ class ExportDialog(QDialog):
|
||||||
index = self.frm.deck.findText(name)
|
index = self.frm.deck.findText(name)
|
||||||
self.frm.deck.setCurrentIndex(index)
|
self.frm.deck.setCurrentIndex(index)
|
||||||
|
|
||||||
def exporterChanged(self, idx):
|
def exporterChanged(self, idx: int) -> None:
|
||||||
self.exporter = self.exporters[idx][1](self.col)
|
self.exporter = self.exporters[idx][1](self.col)
|
||||||
self.isApkg = self.exporter.ext == ".apkg"
|
self.isApkg = self.exporter.ext == ".apkg"
|
||||||
self.isVerbatim = getattr(self.exporter, "verbatim", False)
|
self.isVerbatim = getattr(self.exporter, "verbatim", False)
|
||||||
|
@ -94,7 +94,7 @@ class ExportDialog(QDialog):
|
||||||
# show deck list?
|
# show deck list?
|
||||||
self.frm.deck.setVisible(not self.isVerbatim)
|
self.frm.deck.setVisible(not self.isVerbatim)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
self.exporter.includeSched = self.frm.includeSched.isChecked()
|
self.exporter.includeSched = self.frm.includeSched.isChecked()
|
||||||
self.exporter.includeMedia = self.frm.includeMedia.isChecked()
|
self.exporter.includeMedia = self.frm.includeMedia.isChecked()
|
||||||
self.exporter.includeTags = self.frm.includeTags.isChecked()
|
self.exporter.includeTags = self.frm.includeTags.isChecked()
|
||||||
|
@ -177,7 +177,7 @@ class ExportDialog(QDialog):
|
||||||
|
|
||||||
self.mw.taskman.run_in_background(do_export, on_done)
|
self.mw.taskman.run_in_background(do_export, on_done)
|
||||||
|
|
||||||
def on_export_finished(self):
|
def on_export_finished(self) -> None:
|
||||||
if self.isVerbatim:
|
if self.isVerbatim:
|
||||||
msg = tr(TR.EXPORTING_COLLECTION_EXPORTED)
|
msg = tr(TR.EXPORTING_COLLECTION_EXPORTED)
|
||||||
self.mw.reopen()
|
self.mw.reopen()
|
||||||
|
|
|
@ -41,7 +41,7 @@ class FieldDialog(QDialog):
|
||||||
self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False)
|
self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False)
|
||||||
self.form.buttonBox.button(QDialogButtonBox.Cancel).setAutoDefault(False)
|
self.form.buttonBox.button(QDialogButtonBox.Cancel).setAutoDefault(False)
|
||||||
self.form.buttonBox.button(QDialogButtonBox.Save).setAutoDefault(False)
|
self.form.buttonBox.button(QDialogButtonBox.Save).setAutoDefault(False)
|
||||||
self.currentIdx = None
|
self.currentIdx: Optional[int] = None
|
||||||
self.oldSortField = self.model["sortf"]
|
self.oldSortField = self.model["sortf"]
|
||||||
self.fillFields()
|
self.fillFields()
|
||||||
self.setupSignals()
|
self.setupSignals()
|
||||||
|
@ -52,13 +52,13 @@ class FieldDialog(QDialog):
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def fillFields(self):
|
def fillFields(self) -> None:
|
||||||
self.currentIdx = None
|
self.currentIdx = None
|
||||||
self.form.fieldList.clear()
|
self.form.fieldList.clear()
|
||||||
for c, f in enumerate(self.model["flds"]):
|
for c, f in enumerate(self.model["flds"]):
|
||||||
self.form.fieldList.addItem("{}: {}".format(c + 1, f["name"]))
|
self.form.fieldList.addItem("{}: {}".format(c + 1, f["name"]))
|
||||||
|
|
||||||
def setupSignals(self):
|
def setupSignals(self) -> None:
|
||||||
f = self.form
|
f = self.form
|
||||||
qconnect(f.fieldList.currentRowChanged, self.onRowChange)
|
qconnect(f.fieldList.currentRowChanged, self.onRowChange)
|
||||||
qconnect(f.fieldAdd.clicked, self.onAdd)
|
qconnect(f.fieldAdd.clicked, self.onAdd)
|
||||||
|
@ -86,29 +86,31 @@ class FieldDialog(QDialog):
|
||||||
movePos -= 1
|
movePos -= 1
|
||||||
self.moveField(movePos + 1) # convert to 1 based.
|
self.moveField(movePos + 1) # convert to 1 based.
|
||||||
|
|
||||||
def onRowChange(self, idx):
|
def onRowChange(self, idx: int) -> None:
|
||||||
if idx == -1:
|
if idx == -1:
|
||||||
return
|
return
|
||||||
self.saveField()
|
self.saveField()
|
||||||
self.loadField(idx)
|
self.loadField(idx)
|
||||||
|
|
||||||
def _uniqueName(self, prompt, ignoreOrd=None, old=""):
|
def _uniqueName(
|
||||||
|
self, prompt: str, ignoreOrd: Optional[int] = None, old: str = ""
|
||||||
|
) -> Optional[str]:
|
||||||
txt = getOnlyText(prompt, default=old).replace('"', "").strip()
|
txt = getOnlyText(prompt, default=old).replace('"', "").strip()
|
||||||
if not txt:
|
if not txt:
|
||||||
return
|
return None
|
||||||
if txt[0] in "#^/":
|
if txt[0] in "#^/":
|
||||||
showWarning(tr(TR.FIELDS_NAME_FIRST_LETTER_NOT_VALID))
|
showWarning(tr(TR.FIELDS_NAME_FIRST_LETTER_NOT_VALID))
|
||||||
return
|
return None
|
||||||
for letter in """:{"}""":
|
for letter in """:{"}""":
|
||||||
if letter in txt:
|
if letter in txt:
|
||||||
showWarning(tr(TR.FIELDS_NAME_INVALID_LETTER))
|
showWarning(tr(TR.FIELDS_NAME_INVALID_LETTER))
|
||||||
return
|
return None
|
||||||
for f in self.model["flds"]:
|
for f in self.model["flds"]:
|
||||||
if ignoreOrd is not None and f["ord"] == ignoreOrd:
|
if ignoreOrd is not None and f["ord"] == ignoreOrd:
|
||||||
continue
|
continue
|
||||||
if f["name"] == txt:
|
if f["name"] == txt:
|
||||||
showWarning(tr(TR.FIELDS_THAT_FIELD_NAME_IS_ALREADY_USED))
|
showWarning(tr(TR.FIELDS_THAT_FIELD_NAME_IS_ALREADY_USED))
|
||||||
return
|
return None
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
def onRename(self):
|
def onRename(self):
|
||||||
|
@ -127,7 +129,7 @@ class FieldDialog(QDialog):
|
||||||
self.fillFields()
|
self.fillFields()
|
||||||
self.form.fieldList.setCurrentRow(idx)
|
self.form.fieldList.setCurrentRow(idx)
|
||||||
|
|
||||||
def onAdd(self):
|
def onAdd(self) -> None:
|
||||||
name = self._uniqueName(tr(TR.FIELDS_FIELD_NAME))
|
name = self._uniqueName(tr(TR.FIELDS_FIELD_NAME))
|
||||||
if not name:
|
if not name:
|
||||||
return
|
return
|
||||||
|
@ -185,7 +187,7 @@ class FieldDialog(QDialog):
|
||||||
self.fillFields()
|
self.fillFields()
|
||||||
self.form.fieldList.setCurrentRow(pos - 1)
|
self.form.fieldList.setCurrentRow(pos - 1)
|
||||||
|
|
||||||
def loadField(self, idx):
|
def loadField(self, idx: int) -> None:
|
||||||
self.currentIdx = idx
|
self.currentIdx = idx
|
||||||
fld = self.model["flds"][idx]
|
fld = self.model["flds"][idx]
|
||||||
f = self.form
|
f = self.form
|
||||||
|
@ -195,7 +197,7 @@ class FieldDialog(QDialog):
|
||||||
f.sortField.setChecked(self.model["sortf"] == fld["ord"])
|
f.sortField.setChecked(self.model["sortf"] == fld["ord"])
|
||||||
f.rtl.setChecked(fld["rtl"])
|
f.rtl.setChecked(fld["rtl"])
|
||||||
|
|
||||||
def saveField(self):
|
def saveField(self) -> None:
|
||||||
# not initialized yet?
|
# not initialized yet?
|
||||||
if self.currentIdx is None:
|
if self.currentIdx is None:
|
||||||
return
|
return
|
||||||
|
@ -219,14 +221,14 @@ class FieldDialog(QDialog):
|
||||||
fld["rtl"] = rtl
|
fld["rtl"] = rtl
|
||||||
self.change_tracker.mark_basic()
|
self.change_tracker.mark_basic()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
if self.change_tracker.changed():
|
if self.change_tracker.changed():
|
||||||
if not askUser("Discard changes?"):
|
if not askUser("Discard changes?"):
|
||||||
return
|
return
|
||||||
|
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
self.saveField()
|
self.saveField()
|
||||||
|
|
||||||
def save():
|
def save():
|
||||||
|
|
|
@ -9,12 +9,13 @@ import traceback
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import zipfile
|
import zipfile
|
||||||
from concurrent.futures import Future
|
from concurrent.futures import Future
|
||||||
from typing import Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import anki.importing as importing
|
import anki.importing as importing
|
||||||
import aqt.deckchooser
|
import aqt.deckchooser
|
||||||
import aqt.forms
|
import aqt.forms
|
||||||
import aqt.modelchooser
|
import aqt.modelchooser
|
||||||
|
from anki.importing.apkg import AnkiPackageImporter
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
|
@ -106,14 +107,14 @@ class ImportDialog(QDialog):
|
||||||
self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole)
|
self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole)
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
def setupOptions(self):
|
def setupOptions(self) -> None:
|
||||||
self.model = self.mw.col.models.current()
|
self.model = self.mw.col.models.current()
|
||||||
self.modelChooser = aqt.modelchooser.ModelChooser(
|
self.modelChooser = aqt.modelchooser.ModelChooser(
|
||||||
self.mw, self.frm.modelArea, label=False
|
self.mw, self.frm.modelArea, label=False
|
||||||
)
|
)
|
||||||
self.deck = aqt.deckchooser.DeckChooser(self.mw, self.frm.deckArea, label=False)
|
self.deck = aqt.deckchooser.DeckChooser(self.mw, self.frm.deckArea, label=False)
|
||||||
|
|
||||||
def modelChanged(self, unused=None):
|
def modelChanged(self, unused: Any = None) -> None:
|
||||||
self.importer.model = self.mw.col.models.current()
|
self.importer.model = self.mw.col.models.current()
|
||||||
self.importer.initMapping()
|
self.importer.initMapping()
|
||||||
self.showMapping()
|
self.showMapping()
|
||||||
|
@ -142,7 +143,7 @@ class ImportDialog(QDialog):
|
||||||
self.showMapping(hook=updateDelim)
|
self.showMapping(hook=updateDelim)
|
||||||
self.updateDelimiterButtonText()
|
self.updateDelimiterButtonText()
|
||||||
|
|
||||||
def updateDelimiterButtonText(self):
|
def updateDelimiterButtonText(self) -> None:
|
||||||
if not self.importer.needDelimiter:
|
if not self.importer.needDelimiter:
|
||||||
return
|
return
|
||||||
if self.importer.delimiter:
|
if self.importer.delimiter:
|
||||||
|
@ -164,7 +165,7 @@ class ImportDialog(QDialog):
|
||||||
txt = tr(TR.IMPORTING_FIELDS_SEPARATED_BY, val=d)
|
txt = tr(TR.IMPORTING_FIELDS_SEPARATED_BY, val=d)
|
||||||
self.frm.autoDetect.setText(txt)
|
self.frm.autoDetect.setText(txt)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
self.importer.mapping = self.mapping
|
self.importer.mapping = self.mapping
|
||||||
if not self.importer.mappingOk():
|
if not self.importer.mappingOk():
|
||||||
showWarning(tr(TR.IMPORTING_THE_FIRST_FIELD_OF_THE_NOTE))
|
showWarning(tr(TR.IMPORTING_THE_FIRST_FIELD_OF_THE_NOTE))
|
||||||
|
@ -211,19 +212,21 @@ class ImportDialog(QDialog):
|
||||||
|
|
||||||
self.mw.taskman.run_in_background(self.importer.run, on_done)
|
self.mw.taskman.run_in_background(self.importer.run, on_done)
|
||||||
|
|
||||||
def setupMappingFrame(self):
|
def setupMappingFrame(self) -> None:
|
||||||
# qt seems to have a bug with adding/removing from a grid, so we add
|
# qt seems to have a bug with adding/removing from a grid, so we add
|
||||||
# to a separate object and add/remove that instead
|
# to a separate object and add/remove that instead
|
||||||
self.frame = QFrame(self.frm.mappingArea)
|
self.frame = QFrame(self.frm.mappingArea)
|
||||||
self.frm.mappingArea.setWidget(self.frame)
|
self.frm.mappingArea.setWidget(self.frame)
|
||||||
self.mapbox = QVBoxLayout(self.frame)
|
self.mapbox = QVBoxLayout(self.frame)
|
||||||
self.mapbox.setContentsMargins(0, 0, 0, 0)
|
self.mapbox.setContentsMargins(0, 0, 0, 0)
|
||||||
self.mapwidget = None
|
self.mapwidget: Optional[QWidget] = None
|
||||||
|
|
||||||
def hideMapping(self):
|
def hideMapping(self):
|
||||||
self.frm.mappingGroup.hide()
|
self.frm.mappingGroup.hide()
|
||||||
|
|
||||||
def showMapping(self, keepMapping=False, hook=None):
|
def showMapping(
|
||||||
|
self, keepMapping: bool = False, hook: Optional[Callable] = None
|
||||||
|
) -> None:
|
||||||
if hook:
|
if hook:
|
||||||
hook()
|
hook()
|
||||||
if not keepMapping:
|
if not keepMapping:
|
||||||
|
@ -295,7 +298,7 @@ def showUnicodeWarning():
|
||||||
showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8))
|
showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8))
|
||||||
|
|
||||||
|
|
||||||
def onImport(mw):
|
def onImport(mw: AnkiQt) -> None:
|
||||||
filt = ";;".join([x[0] for x in importing.Importers])
|
filt = ";;".join([x[0] for x in importing.Importers])
|
||||||
file = getFile(mw, tr(TR.ACTIONS_IMPORT), None, key="import", filter=filt)
|
file = getFile(mw, tr(TR.ACTIONS_IMPORT), None, key="import", filter=filt)
|
||||||
if not file:
|
if not file:
|
||||||
|
@ -314,7 +317,7 @@ def onImport(mw):
|
||||||
importFile(mw, file)
|
importFile(mw, file)
|
||||||
|
|
||||||
|
|
||||||
def importFile(mw, file):
|
def importFile(mw: AnkiQt, file: str) -> None:
|
||||||
importerClass = None
|
importerClass = None
|
||||||
done = False
|
done = False
|
||||||
for i in importing.Importers:
|
for i in importing.Importers:
|
||||||
|
@ -406,7 +409,7 @@ def invalidZipMsg():
|
||||||
return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO)
|
return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO)
|
||||||
|
|
||||||
|
|
||||||
def setupApkgImport(mw, importer):
|
def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool:
|
||||||
base = os.path.basename(importer.file).lower()
|
base = os.path.basename(importer.file).lower()
|
||||||
full = (
|
full = (
|
||||||
(base == "collection.apkg")
|
(base == "collection.apkg")
|
||||||
|
@ -424,6 +427,7 @@ def setupApkgImport(mw, importer):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
replaceWithApkg(mw, importer.file, mw.restoringBackup)
|
replaceWithApkg(mw, importer.file, mw.restoringBackup)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def replaceWithApkg(mw, file, backup):
|
def replaceWithApkg(mw, file, backup):
|
||||||
|
|
|
@ -1141,7 +1141,7 @@ title="%s" %s>%s</button>""" % (
|
||||||
# Cramming
|
# Cramming
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def onCram(self, search=""):
|
def onCram(self, search: str = "") -> None:
|
||||||
import aqt.dyndeckconf
|
import aqt.dyndeckconf
|
||||||
|
|
||||||
n = 1
|
n = 1
|
||||||
|
|
|
@ -26,7 +26,7 @@ from aqt.qt import *
|
||||||
from aqt.utils import aqt_data_folder
|
from aqt.utils import aqt_data_folder
|
||||||
|
|
||||||
|
|
||||||
def _getExportFolder():
|
def _getExportFolder() -> str:
|
||||||
data_folder = aqt_data_folder()
|
data_folder = aqt_data_folder()
|
||||||
webInSrcFolder = os.path.abspath(os.path.join(data_folder, "web"))
|
webInSrcFolder = os.path.abspath(os.path.join(data_folder, "web"))
|
||||||
if os.path.exists(webInSrcFolder):
|
if os.path.exists(webInSrcFolder):
|
||||||
|
@ -83,7 +83,7 @@ class MediaServer(threading.Thread):
|
||||||
if not self.is_shutdown:
|
if not self.is_shutdown:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self) -> None:
|
||||||
self.is_shutdown = True
|
self.is_shutdown = True
|
||||||
sockets = list(self.server._map.values()) # type: ignore
|
sockets = list(self.server._map.values()) # type: ignore
|
||||||
for socket in sockets:
|
for socket in sockets:
|
||||||
|
@ -91,7 +91,7 @@ class MediaServer(threading.Thread):
|
||||||
# https://github.com/Pylons/webtest/blob/4b8a3ebf984185ff4fefb31b4d0cf82682e1fcf7/webtest/http.py#L93-L104
|
# https://github.com/Pylons/webtest/blob/4b8a3ebf984185ff4fefb31b4d0cf82682e1fcf7/webtest/http.py#L93-L104
|
||||||
self.server.task_dispatcher.shutdown()
|
self.server.task_dispatcher.shutdown()
|
||||||
|
|
||||||
def getPort(self):
|
def getPort(self) -> int:
|
||||||
self._ready.wait()
|
self._ready.wait()
|
||||||
return int(self.server.effective_port) # type: ignore
|
return int(self.server.effective_port) # type: ignore
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ class Models(QDialog):
|
||||||
# Models
|
# Models
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def maybe_select_provided_notetype(self):
|
def maybe_select_provided_notetype(self) -> None:
|
||||||
if not self.selected_notetype_id:
|
if not self.selected_notetype_id:
|
||||||
self.form.modelsList.setCurrentRow(0)
|
self.form.modelsList.setCurrentRow(0)
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional
|
from typing import Any, Callable, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import SearchTerm
|
from anki.collection import SearchTerm
|
||||||
|
@ -45,13 +45,13 @@ class Overview:
|
||||||
self.web = mw.web
|
self.web = mw.web
|
||||||
self.bottom = BottomBar(mw, mw.bottomWeb)
|
self.bottom = BottomBar(mw, mw.bottomWeb)
|
||||||
|
|
||||||
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.mw.setStateShortcuts(self._shortcutKeys())
|
self.mw.setStateShortcuts(self._shortcutKeys())
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self) -> None:
|
||||||
self.mw.col.reset()
|
self.mw.col.reset()
|
||||||
self._renderPage()
|
self._renderPage()
|
||||||
self._renderBottom()
|
self._renderBottom()
|
||||||
|
@ -61,7 +61,7 @@ class Overview:
|
||||||
# Handlers
|
# Handlers
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
def _linkHandler(self, url):
|
def _linkHandler(self, url: str) -> bool:
|
||||||
if url == "study":
|
if url == "study":
|
||||||
self.mw.col.startTimebox()
|
self.mw.col.startTimebox()
|
||||||
self.mw.moveToState("review")
|
self.mw.moveToState("review")
|
||||||
|
@ -92,7 +92,7 @@ class Overview:
|
||||||
openLink(url)
|
openLink(url)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _shortcutKeys(self):
|
def _shortcutKeys(self) -> List[Tuple[str, Callable]]:
|
||||||
return [
|
return [
|
||||||
("o", self.mw.onDeckConf),
|
("o", self.mw.onDeckConf),
|
||||||
("r", self.onRebuildKey),
|
("r", self.onRebuildKey),
|
||||||
|
@ -101,7 +101,7 @@ class Overview:
|
||||||
("u", self.onUnbury),
|
("u", self.onUnbury),
|
||||||
]
|
]
|
||||||
|
|
||||||
def _filteredDeck(self):
|
def _filteredDeck(self) -> int:
|
||||||
return self.mw.col.decks.current()["dyn"]
|
return self.mw.col.decks.current()["dyn"]
|
||||||
|
|
||||||
def onRebuildKey(self):
|
def onRebuildKey(self):
|
||||||
|
@ -114,7 +114,7 @@ class Overview:
|
||||||
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()
|
||||||
|
|
||||||
def onCustomStudyKey(self):
|
def onCustomStudyKey(self) -> None:
|
||||||
if not self._filteredDeck():
|
if not self._filteredDeck():
|
||||||
self.onStudyMore()
|
self.onStudyMore()
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ class Overview:
|
||||||
# HTML
|
# HTML
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
def _renderPage(self):
|
def _renderPage(self) -> None:
|
||||||
but = self.mw.button
|
but = self.mw.button
|
||||||
deck = self.mw.col.decks.current()
|
deck = self.mw.col.decks.current()
|
||||||
self.sid = deck.get("sharedFrom")
|
self.sid = deck.get("sharedFrom")
|
||||||
|
@ -177,10 +177,10 @@ class Overview:
|
||||||
context=self,
|
context=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _show_finished_screen(self):
|
def _show_finished_screen(self) -> None:
|
||||||
self.web.load_ts_page("congrats")
|
self.web.load_ts_page("congrats")
|
||||||
|
|
||||||
def _desc(self, deck):
|
def _desc(self, deck: Dict[str, Any]) -> str:
|
||||||
if deck["dyn"]:
|
if deck["dyn"]:
|
||||||
desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR)
|
desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR)
|
||||||
desc += " " + tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO)
|
desc += " " + tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO)
|
||||||
|
@ -229,7 +229,7 @@ class Overview:
|
||||||
# Bottom area
|
# Bottom area
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def _renderBottom(self):
|
def _renderBottom(self) -> None:
|
||||||
links = [
|
links = [
|
||||||
["O", "opts", tr(TR.ACTIONS_OPTIONS)],
|
["O", "opts", tr(TR.ACTIONS_OPTIONS)],
|
||||||
]
|
]
|
||||||
|
@ -256,7 +256,7 @@ class Overview:
|
||||||
# Studying more
|
# Studying more
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def onStudyMore(self):
|
def onStudyMore(self) -> None:
|
||||||
import aqt.customstudy
|
import aqt.customstudy
|
||||||
|
|
||||||
aqt.customstudy.CustomStudy(self.mw)
|
aqt.customstudy.CustomStudy(self.mw)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from typing import Any, Callable, Optional, Union
|
from typing import Any, Callable, Optional, Tuple, Union
|
||||||
|
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.collection import ConfigBoolKey
|
from anki.collection import ConfigBoolKey
|
||||||
|
@ -19,6 +19,7 @@ from aqt.qt import (
|
||||||
QPixmap,
|
QPixmap,
|
||||||
QShortcut,
|
QShortcut,
|
||||||
Qt,
|
Qt,
|
||||||
|
QTimer,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
QWidget,
|
QWidget,
|
||||||
qconnect,
|
qconnect,
|
||||||
|
@ -29,12 +30,14 @@ from aqt.theme import theme_manager
|
||||||
from aqt.utils import TR, disable_help_button, restoreGeom, saveGeom, tr
|
from aqt.utils import TR, disable_help_button, restoreGeom, saveGeom, tr
|
||||||
from aqt.webview import AnkiWebView
|
from aqt.webview import AnkiWebView
|
||||||
|
|
||||||
|
LastStateAndMod = Tuple[str, int, int]
|
||||||
|
|
||||||
|
|
||||||
class Previewer(QDialog):
|
class Previewer(QDialog):
|
||||||
_last_state = None
|
_last_state: Optional[LastStateAndMod] = None
|
||||||
_card_changed = False
|
_card_changed = False
|
||||||
_last_render: Union[int, float] = 0
|
_last_render: Union[int, float] = 0
|
||||||
_timer = 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]):
|
||||||
|
@ -54,7 +57,7 @@ class Previewer(QDialog):
|
||||||
def card_changed(self) -> bool:
|
def card_changed(self) -> bool:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def open(self):
|
def open(self) -> None:
|
||||||
self._state = "question"
|
self._state = "question"
|
||||||
self._last_state = None
|
self._last_state = None
|
||||||
self._create_gui()
|
self._create_gui()
|
||||||
|
@ -62,7 +65,7 @@ class Previewer(QDialog):
|
||||||
self.render_card()
|
self.render_card()
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def _create_gui(self):
|
def _create_gui(self) -> None:
|
||||||
self.setWindowTitle(tr(TR.ACTIONS_PREVIEW))
|
self.setWindowTitle(tr(TR.ACTIONS_PREVIEW))
|
||||||
|
|
||||||
self.close_shortcut = QShortcut(QKeySequence("Ctrl+Shift+P"), self)
|
self.close_shortcut = QShortcut(QKeySequence("Ctrl+Shift+P"), self)
|
||||||
|
@ -98,25 +101,25 @@ class Previewer(QDialog):
|
||||||
self.setLayout(self.vbox)
|
self.setLayout(self.vbox)
|
||||||
restoreGeom(self, "preview")
|
restoreGeom(self, "preview")
|
||||||
|
|
||||||
def _on_finished(self, ok):
|
def _on_finished(self, ok: int) -> None:
|
||||||
saveGeom(self, "preview")
|
saveGeom(self, "preview")
|
||||||
self.mw.progress.timer(100, self._on_close, False)
|
self.mw.progress.timer(100, self._on_close, False)
|
||||||
|
|
||||||
def _on_replay_audio(self):
|
def _on_replay_audio(self) -> None:
|
||||||
if self._state == "question":
|
if self._state == "question":
|
||||||
replay_audio(self.card(), True)
|
replay_audio(self.card(), True)
|
||||||
elif self._state == "answer":
|
elif self._state == "answer":
|
||||||
replay_audio(self.card(), False)
|
replay_audio(self.card(), False)
|
||||||
|
|
||||||
def close(self):
|
def close(self) -> None:
|
||||||
self._on_close()
|
self._on_close()
|
||||||
super().close()
|
super().close()
|
||||||
|
|
||||||
def _on_close(self):
|
def _on_close(self) -> None:
|
||||||
self._open = False
|
self._open = False
|
||||||
self._close_callback()
|
self._close_callback()
|
||||||
|
|
||||||
def _setup_web_view(self):
|
def _setup_web_view(self) -> None:
|
||||||
jsinc = [
|
jsinc = [
|
||||||
"js/vendor/jquery.min.js",
|
"js/vendor/jquery.min.js",
|
||||||
"js/vendor/css_browser_selector.min.js",
|
"js/vendor/css_browser_selector.min.js",
|
||||||
|
@ -136,7 +139,7 @@ class Previewer(QDialog):
|
||||||
if cmd.startswith("play:"):
|
if cmd.startswith("play:"):
|
||||||
play_clicked_audio(cmd, self.card())
|
play_clicked_audio(cmd, self.card())
|
||||||
|
|
||||||
def render_card(self):
|
def render_card(self) -> None:
|
||||||
self.cancel_timer()
|
self.cancel_timer()
|
||||||
# Keep track of whether render() has ever been called
|
# Keep track of whether render() has ever been called
|
||||||
# with cardChanged=True since the last successful render
|
# with cardChanged=True since the last successful render
|
||||||
|
@ -151,7 +154,7 @@ class Previewer(QDialog):
|
||||||
else:
|
else:
|
||||||
self._render_scheduled()
|
self._render_scheduled()
|
||||||
|
|
||||||
def cancel_timer(self):
|
def cancel_timer(self) -> None:
|
||||||
if self._timer:
|
if self._timer:
|
||||||
self._timer.stop()
|
self._timer.stop()
|
||||||
self._timer = None
|
self._timer = None
|
||||||
|
@ -214,7 +217,7 @@ class Previewer(QDialog):
|
||||||
self._web.eval("{}({},'{}');".format(func, json.dumps(txt), bodyclass))
|
self._web.eval("{}({},'{}');".format(func, json.dumps(txt), bodyclass))
|
||||||
self._card_changed = False
|
self._card_changed = False
|
||||||
|
|
||||||
def _on_show_both_sides(self, toggle):
|
def _on_show_both_sides(self, toggle: bool) -> None:
|
||||||
self._show_both_sides = toggle
|
self._show_both_sides = toggle
|
||||||
self.mw.col.set_config_bool(ConfigBoolKey.PREVIEW_BOTH_SIDES, toggle)
|
self.mw.col.set_config_bool(ConfigBoolKey.PREVIEW_BOTH_SIDES, toggle)
|
||||||
self.mw.col.setMod()
|
self.mw.col.setMod()
|
||||||
|
@ -222,7 +225,7 @@ class Previewer(QDialog):
|
||||||
self._state = "question"
|
self._state = "question"
|
||||||
self.render_card()
|
self.render_card()
|
||||||
|
|
||||||
def _state_and_mod(self):
|
def _state_and_mod(self) -> Tuple[str, int, int]:
|
||||||
c = self.card()
|
c = self.card()
|
||||||
n = c.note()
|
n = c.note()
|
||||||
n.load()
|
n.load()
|
||||||
|
@ -241,7 +244,7 @@ class MultiCardPreviewer(Previewer):
|
||||||
# need to state explicitly it's not implement to avoid W0223
|
# need to state explicitly it's not implement to avoid W0223
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _create_gui(self):
|
def _create_gui(self) -> None:
|
||||||
super()._create_gui()
|
super()._create_gui()
|
||||||
self._prev = self.bbox.addButton("<", QDialogButtonBox.ActionRole)
|
self._prev = self.bbox.addButton("<", QDialogButtonBox.ActionRole)
|
||||||
self._prev.setAutoDefault(False)
|
self._prev.setAutoDefault(False)
|
||||||
|
@ -266,7 +269,7 @@ class MultiCardPreviewer(Previewer):
|
||||||
def _on_prev_card(self):
|
def _on_prev_card(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _on_next(self):
|
def _on_next(self) -> None:
|
||||||
if self._state == "question":
|
if self._state == "question":
|
||||||
self._state = "answer"
|
self._state = "answer"
|
||||||
self.render_card()
|
self.render_card()
|
||||||
|
@ -276,19 +279,19 @@ class MultiCardPreviewer(Previewer):
|
||||||
def _on_next_card(self):
|
def _on_next_card(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _updateButtons(self):
|
def _updateButtons(self) -> None:
|
||||||
if not self._open:
|
if not self._open:
|
||||||
return
|
return
|
||||||
self._prev.setEnabled(self._should_enable_prev())
|
self._prev.setEnabled(self._should_enable_prev())
|
||||||
self._next.setEnabled(self._should_enable_next())
|
self._next.setEnabled(self._should_enable_next())
|
||||||
|
|
||||||
def _should_enable_prev(self):
|
def _should_enable_prev(self) -> bool:
|
||||||
return self._state == "answer" and not self._show_both_sides
|
return self._state == "answer" and not self._show_both_sides
|
||||||
|
|
||||||
def _should_enable_next(self):
|
def _should_enable_next(self) -> bool:
|
||||||
return self._state == "question"
|
return self._state == "question"
|
||||||
|
|
||||||
def _on_close(self):
|
def _on_close(self) -> None:
|
||||||
super()._on_close()
|
super()._on_close()
|
||||||
self._prev = None
|
self._prev = None
|
||||||
self._next = None
|
self._next = None
|
||||||
|
@ -317,15 +320,15 @@ class BrowserPreviewer(MultiCardPreviewer):
|
||||||
lambda: self._parent._moveCur(QAbstractItemView.MoveUp)
|
lambda: self._parent._moveCur(QAbstractItemView.MoveUp)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _on_next_card(self):
|
def _on_next_card(self) -> None:
|
||||||
self._parent.editor.saveNow(
|
self._parent.editor.saveNow(
|
||||||
lambda: self._parent._moveCur(QAbstractItemView.MoveDown)
|
lambda: self._parent._moveCur(QAbstractItemView.MoveDown)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _should_enable_prev(self):
|
def _should_enable_prev(self) -> bool:
|
||||||
return super()._should_enable_prev() or self._parent.currentRow() > 0
|
return super()._should_enable_prev() or self._parent.currentRow() > 0
|
||||||
|
|
||||||
def _should_enable_next(self):
|
def _should_enable_next(self) -> bool:
|
||||||
return (
|
return (
|
||||||
super()._should_enable_next()
|
super()._should_enable_next()
|
||||||
or self._parent.currentRow() < self._parent.model.rowCount(None) - 1
|
or self._parent.currentRow() < self._parent.model.rowCount(None) - 1
|
||||||
|
|
|
@ -119,11 +119,11 @@ class AnkiRestart(SystemExit):
|
||||||
|
|
||||||
|
|
||||||
class ProfileManager:
|
class ProfileManager:
|
||||||
def __init__(self, base=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 = {}
|
self.session: Dict[str, Any] = {}
|
||||||
self.name = None
|
self.name: Optional[str] = None
|
||||||
self.db = None
|
self.db: Optional[DB] = None
|
||||||
self.profile: Optional[Dict] = None
|
self.profile: Optional[Dict] = None
|
||||||
# instantiate base folder
|
# instantiate base folder
|
||||||
self.base: str
|
self.base: str
|
||||||
|
@ -170,7 +170,7 @@ class ProfileManager:
|
||||||
return p
|
return p
|
||||||
return os.path.expanduser("~/Documents/Anki")
|
return os.path.expanduser("~/Documents/Anki")
|
||||||
|
|
||||||
def maybeMigrateFolder(self):
|
def maybeMigrateFolder(self) -> None:
|
||||||
newBase = self.base
|
newBase = self.base
|
||||||
oldBase = self._oldFolderLocation()
|
oldBase = self._oldFolderLocation()
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ class ProfileManager:
|
||||||
confirmation.setText(
|
confirmation.setText(
|
||||||
"Anki needs to move its data folder from Documents/Anki to a new location. Proceed?"
|
"Anki needs to move its data folder from Documents/Anki to a new location. Proceed?"
|
||||||
)
|
)
|
||||||
retval = confirmation.exec()
|
retval = confirmation.exec_()
|
||||||
|
|
||||||
if retval == QMessageBox.Ok:
|
if retval == QMessageBox.Ok:
|
||||||
progress = QMessageBox()
|
progress = QMessageBox()
|
||||||
|
@ -228,7 +228,7 @@ class ProfileManager:
|
||||||
completion.setWindowTitle(window_title)
|
completion.setWindowTitle(window_title)
|
||||||
completion.setText("Migration complete. Please start Anki again.")
|
completion.setText("Migration complete. Please start Anki again.")
|
||||||
completion.show()
|
completion.show()
|
||||||
completion.exec()
|
completion.exec_()
|
||||||
else:
|
else:
|
||||||
diag = QMessageBox()
|
diag = QMessageBox()
|
||||||
diag.setIcon(QMessageBox.Warning)
|
diag.setIcon(QMessageBox.Warning)
|
||||||
|
@ -239,7 +239,7 @@ class ProfileManager:
|
||||||
"Migration aborted. If you would like to keep the old folder location, please "
|
"Migration aborted. If you would like to keep the old folder location, please "
|
||||||
"see the Startup Options section of the manual. Anki will now quit."
|
"see the Startup Options section of the manual. Anki will now quit."
|
||||||
)
|
)
|
||||||
diag.exec()
|
diag.exec_()
|
||||||
|
|
||||||
raise AnkiRestart(exitcode=0)
|
raise AnkiRestart(exitcode=0)
|
||||||
|
|
||||||
|
@ -424,7 +424,7 @@ class ProfileManager:
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def _setBaseFolder(self, cmdlineBase: None) -> None:
|
def _setBaseFolder(self, cmdlineBase: Optional[str]) -> None:
|
||||||
if cmdlineBase:
|
if cmdlineBase:
|
||||||
self.base = os.path.abspath(cmdlineBase)
|
self.base = os.path.abspath(cmdlineBase)
|
||||||
elif os.environ.get("ANKI_BASE"):
|
elif os.environ.get("ANKI_BASE"):
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from typing import Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
import aqt.forms
|
import aqt.forms
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -15,13 +15,13 @@ from aqt.utils import TR, disable_help_button, tr
|
||||||
|
|
||||||
|
|
||||||
class ProgressManager:
|
class ProgressManager:
|
||||||
def __init__(self, mw):
|
def __init__(self, mw: aqt.AnkiQt) -> None:
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.app = QApplication.instance()
|
self.app = QApplication.instance()
|
||||||
self.inDB = False
|
self.inDB = False
|
||||||
self.blockUpdates = False
|
self.blockUpdates = False
|
||||||
self._show_timer: Optional[QTimer] = None
|
self._show_timer: Optional[QTimer] = None
|
||||||
self._win = None
|
self._win: Optional[ProgressDialog] = None
|
||||||
self._levels = 0
|
self._levels = 0
|
||||||
|
|
||||||
# Safer timers
|
# Safer timers
|
||||||
|
@ -29,7 +29,9 @@ class ProgressManager:
|
||||||
# A custom timer which avoids firing while a progress dialog is active
|
# A custom timer which avoids firing while a progress dialog is active
|
||||||
# (likely due to some long-running DB operation)
|
# (likely due to some long-running DB operation)
|
||||||
|
|
||||||
def timer(self, ms, func, repeat, requiresCollection=True):
|
def timer(
|
||||||
|
self, ms: int, func: Callable, repeat: bool, requiresCollection: bool = True
|
||||||
|
) -> QTimer:
|
||||||
"""Create and start a standard Anki timer.
|
"""Create and start a standard Anki timer.
|
||||||
|
|
||||||
If the timer fires while a progress window is shown:
|
If the timer fires while a progress window is shown:
|
||||||
|
@ -136,7 +138,7 @@ class ProgressManager:
|
||||||
self._updating = False
|
self._updating = False
|
||||||
self._lastUpdate = time.time()
|
self._lastUpdate = time.time()
|
||||||
|
|
||||||
def finish(self):
|
def finish(self) -> None:
|
||||||
self._levels -= 1
|
self._levels -= 1
|
||||||
self._levels = max(0, self._levels)
|
self._levels = max(0, self._levels)
|
||||||
if self._levels == 0:
|
if self._levels == 0:
|
||||||
|
@ -147,13 +149,13 @@ class ProgressManager:
|
||||||
self._show_timer.stop()
|
self._show_timer.stop()
|
||||||
self._show_timer = None
|
self._show_timer = None
|
||||||
|
|
||||||
def clear(self):
|
def clear(self) -> None:
|
||||||
"Restore the interface after an error."
|
"Restore the interface after an error."
|
||||||
if self._levels:
|
if self._levels:
|
||||||
self._levels = 1
|
self._levels = 1
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
def _maybeShow(self):
|
def _maybeShow(self) -> None:
|
||||||
if not self._levels:
|
if not self._levels:
|
||||||
return
|
return
|
||||||
if self._shown:
|
if self._shown:
|
||||||
|
@ -181,17 +183,17 @@ class ProgressManager:
|
||||||
self._win = None
|
self._win = None
|
||||||
self._shown = 0
|
self._shown = 0
|
||||||
|
|
||||||
def _setBusy(self):
|
def _setBusy(self) -> None:
|
||||||
self.mw.app.setOverrideCursor(QCursor(Qt.WaitCursor))
|
self.mw.app.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
|
|
||||||
def _unsetBusy(self):
|
def _unsetBusy(self) -> None:
|
||||||
self.app.restoreOverrideCursor()
|
self.app.restoreOverrideCursor()
|
||||||
|
|
||||||
def busy(self):
|
def busy(self) -> int:
|
||||||
"True if processing."
|
"True if processing."
|
||||||
return self._levels
|
return self._levels
|
||||||
|
|
||||||
def _on_show_timer(self):
|
def _on_show_timer(self) -> None:
|
||||||
self._show_timer = None
|
self._show_timer = None
|
||||||
self._showWin()
|
self._showWin()
|
||||||
|
|
||||||
|
@ -209,7 +211,7 @@ class ProgressManager:
|
||||||
|
|
||||||
|
|
||||||
class ProgressDialog(QDialog):
|
class ProgressDialog(QDialog):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent: QWidget) -> None:
|
||||||
QDialog.__init__(self, parent)
|
QDialog.__init__(self, parent)
|
||||||
disable_help_button(self)
|
disable_help_button(self)
|
||||||
self.form = aqt.forms.progress.Ui_Dialog()
|
self.form = aqt.forms.progress.Ui_Dialog()
|
||||||
|
@ -219,7 +221,7 @@ class ProgressDialog(QDialog):
|
||||||
# required for smooth progress bars
|
# required for smooth progress bars
|
||||||
self.form.progressBar.setStyleSheet("QProgressBar::chunk { width: 1px; }")
|
self.form.progressBar.setStyleSheet("QProgressBar::chunk { width: 1px; }")
|
||||||
|
|
||||||
def cancel(self):
|
def cancel(self) -> None:
|
||||||
self._closingDown = True
|
self._closingDown = True
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
|
|
|
@ -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 Callable, List, Optional, Tuple, Union
|
from typing import Any, Callable, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
@ -697,7 +697,7 @@ time = %(time)d;
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
# note the shortcuts listed here also need to be defined above
|
# note the shortcuts listed here also need to be defined above
|
||||||
def _contextMenu(self):
|
def _contextMenu(self) -> List[Any]:
|
||||||
currentFlag = self.card and self.card.userFlag()
|
currentFlag = self.card and self.card.userFlag()
|
||||||
opts = [
|
opts = [
|
||||||
[
|
[
|
||||||
|
|
|
@ -20,7 +20,7 @@ class ChangeTracker:
|
||||||
def __init__(self, mw: AnkiQt):
|
def __init__(self, mw: AnkiQt):
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
|
|
||||||
def mark_basic(self):
|
def mark_basic(self) -> None:
|
||||||
if self._changed == Change.NO_CHANGE:
|
if self._changed == Change.NO_CHANGE:
|
||||||
self._changed = Change.BASIC_CHANGE
|
self._changed = Change.BASIC_CHANGE
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ class NewDeckStats(QDialog):
|
||||||
self.form.web.set_bridge_command(self._on_bridge_cmd, self)
|
self.form.web.set_bridge_command(self._on_bridge_cmd, self)
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.form.web = None
|
self.form.web = None
|
||||||
saveGeom(self, self.name)
|
saveGeom(self, self.name)
|
||||||
aqt.dialogs.markClosed("NewDeckStats")
|
aqt.dialogs.markClosed("NewDeckStats")
|
||||||
|
@ -98,14 +98,14 @@ class NewDeckStats(QDialog):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self) -> None:
|
||||||
self.form.web.load_ts_page("graphs")
|
self.form.web.load_ts_page("graphs")
|
||||||
|
|
||||||
|
|
||||||
class DeckStats(QDialog):
|
class DeckStats(QDialog):
|
||||||
"""Legacy deck stats, used by some add-ons."""
|
"""Legacy deck stats, used by some add-ons."""
|
||||||
|
|
||||||
def __init__(self, mw):
|
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
|
||||||
|
@ -143,7 +143,7 @@ class DeckStats(QDialog):
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self) -> None:
|
||||||
self.form.web = None
|
self.form.web = None
|
||||||
saveGeom(self, self.name)
|
saveGeom(self, self.name)
|
||||||
aqt.dialogs.markClosed("DeckStats")
|
aqt.dialogs.markClosed("DeckStats")
|
||||||
|
@ -173,15 +173,15 @@ class DeckStats(QDialog):
|
||||||
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: int) -> None:
|
||||||
self.period = n
|
self.period = n
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def changeScope(self, type):
|
def changeScope(self, type: str) -> None:
|
||||||
self.wholeCollection = type == "collection"
|
self.wholeCollection = type == "collection"
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self) -> None:
|
||||||
self.mw.progress.start(parent=self)
|
self.mw.progress.start(parent=self)
|
||||||
stats = self.mw.col.stats()
|
stats = self.mw.col.stats()
|
||||||
stats.wholeCollection = self.wholeCollection
|
stats.wholeCollection = self.wholeCollection
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
# -*- 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 typing import Optional
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -109,7 +111,7 @@ class StudyDeck(QDialog):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def redraw(self, filt, focus=None):
|
def redraw(self, filt: str, focus: Optional[str] = None) -> None:
|
||||||
self.filt = filt
|
self.filt = filt
|
||||||
self.focus = focus
|
self.focus = focus
|
||||||
self.names = [n for n in self.origNames if self._matches(n, filt)]
|
self.names = [n for n in self.origNames if self._matches(n, filt)]
|
||||||
|
@ -123,7 +125,7 @@ class StudyDeck(QDialog):
|
||||||
l.setCurrentRow(idx)
|
l.setCurrentRow(idx)
|
||||||
l.scrollToItem(l.item(idx), QAbstractItemView.PositionAtCenter)
|
l.scrollToItem(l.item(idx), QAbstractItemView.PositionAtCenter)
|
||||||
|
|
||||||
def _matches(self, name, filt):
|
def _matches(self, name: str, filt: str) -> bool:
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
filt = filt.lower()
|
filt = filt.lower()
|
||||||
if not filt:
|
if not filt:
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from typing import Iterable, List, Optional, Union
|
||||||
|
|
||||||
|
from anki.collection import Collection
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
|
||||||
|
@ -15,9 +17,9 @@ class TagEdit(QLineEdit):
|
||||||
lostFocus = pyqtSignal()
|
lostFocus = pyqtSignal()
|
||||||
|
|
||||||
# 0 = tags, 1 = decks
|
# 0 = tags, 1 = decks
|
||||||
def __init__(self, parent, type=0):
|
def __init__(self, parent: QDialog, type: int = 0) -> None:
|
||||||
QLineEdit.__init__(self, parent)
|
QLineEdit.__init__(self, parent)
|
||||||
self.col = None
|
self.col: Optional[Collection] = None
|
||||||
self.model = QStringListModel()
|
self.model = QStringListModel()
|
||||||
self.type = type
|
self.type = type
|
||||||
if type == 0:
|
if type == 0:
|
||||||
|
@ -28,19 +30,20 @@ class TagEdit(QLineEdit):
|
||||||
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
|
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
|
||||||
self.setCompleter(self.completer)
|
self.setCompleter(self.completer)
|
||||||
|
|
||||||
def setCol(self, col):
|
def setCol(self, col: Collection) -> None:
|
||||||
"Set the current col, updating list of available tags."
|
"Set the current col, updating list of available tags."
|
||||||
self.col = col
|
self.col = col
|
||||||
|
l: Iterable[str]
|
||||||
if self.type == 0:
|
if self.type == 0:
|
||||||
l = self.col.tags.all()
|
l = self.col.tags.all()
|
||||||
else:
|
else:
|
||||||
l = (d.name for d in self.col.decks.all_names_and_ids())
|
l = (d.name for d in self.col.decks.all_names_and_ids())
|
||||||
self.model.setStringList(l)
|
self.model.setStringList(l)
|
||||||
|
|
||||||
def focusInEvent(self, evt):
|
def focusInEvent(self, evt: QFocusEvent) -> None:
|
||||||
QLineEdit.focusInEvent(self, evt)
|
QLineEdit.focusInEvent(self, evt)
|
||||||
|
|
||||||
def keyPressEvent(self, evt):
|
def keyPressEvent(self, evt: QKeyEvent) -> None:
|
||||||
if evt.key() in (Qt.Key_Up, Qt.Key_Down):
|
if evt.key() in (Qt.Key_Up, Qt.Key_Down):
|
||||||
# show completer on arrow key up/down
|
# show completer on arrow key up/down
|
||||||
if not self.completer.popup().isVisible():
|
if not self.completer.popup().isVisible():
|
||||||
|
@ -85,7 +88,7 @@ class TagEdit(QLineEdit):
|
||||||
self.showCompleter()
|
self.showCompleter()
|
||||||
gui_hooks.tag_editor_did_process_key(self, evt)
|
gui_hooks.tag_editor_did_process_key(self, evt)
|
||||||
|
|
||||||
def showCompleter(self):
|
def showCompleter(self) -> None:
|
||||||
self.completer.setCompletionPrefix(self.text())
|
self.completer.setCompletionPrefix(self.text())
|
||||||
self.completer.complete()
|
self.completer.complete()
|
||||||
|
|
||||||
|
@ -94,20 +97,26 @@ class TagEdit(QLineEdit):
|
||||||
self.lostFocus.emit() # type: ignore
|
self.lostFocus.emit() # type: ignore
|
||||||
self.completer.popup().hide()
|
self.completer.popup().hide()
|
||||||
|
|
||||||
def hideCompleter(self):
|
def hideCompleter(self) -> None:
|
||||||
if sip.isdeleted(self.completer):
|
if sip.isdeleted(self.completer):
|
||||||
return
|
return
|
||||||
self.completer.popup().hide()
|
self.completer.popup().hide()
|
||||||
|
|
||||||
|
|
||||||
class TagCompleter(QCompleter):
|
class TagCompleter(QCompleter):
|
||||||
def __init__(self, model, parent, edit, *args):
|
def __init__(
|
||||||
|
self,
|
||||||
|
model: QStringListModel,
|
||||||
|
parent: QWidget,
|
||||||
|
edit: TagEdit,
|
||||||
|
*args,
|
||||||
|
) -> None:
|
||||||
QCompleter.__init__(self, model, parent)
|
QCompleter.__init__(self, model, parent)
|
||||||
self.tags = []
|
self.tags: List[str] = []
|
||||||
self.edit = edit
|
self.edit = edit
|
||||||
self.cursor = None
|
self.cursor: Optional[int] = None
|
||||||
|
|
||||||
def splitPath(self, tags):
|
def splitPath(self, tags: str) -> List[str]:
|
||||||
stripped_tags = tags.strip()
|
stripped_tags = tags.strip()
|
||||||
stripped_tags = re.sub(" +", " ", stripped_tags)
|
stripped_tags = re.sub(" +", " ", stripped_tags)
|
||||||
self.tags = self.edit.col.tags.split(stripped_tags)
|
self.tags = self.edit.col.tags.split(stripped_tags)
|
||||||
|
@ -119,7 +128,7 @@ class TagCompleter(QCompleter):
|
||||||
self.cursor = stripped_tags.count(" ", 0, p)
|
self.cursor = stripped_tags.count(" ", 0, p)
|
||||||
return [self.tags[self.cursor]]
|
return [self.tags[self.cursor]]
|
||||||
|
|
||||||
def pathFromIndex(self, idx):
|
def pathFromIndex(self, idx: QModelIndex) -> str:
|
||||||
if self.cursor is None:
|
if self.cursor is None:
|
||||||
return self.edit.text()
|
return self.edit.text()
|
||||||
ret = QCompleter.pathFromIndex(self, idx)
|
ret = QCompleter.pathFromIndex(self, idx)
|
||||||
|
|
|
@ -3,14 +3,17 @@
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
|
from aqt.customstudy import CustomStudy
|
||||||
|
from aqt.main import AnkiQt
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import disable_help_button, restoreGeom, saveGeom
|
from aqt.utils import disable_help_button, restoreGeom, saveGeom
|
||||||
|
|
||||||
|
|
||||||
class TagLimit(QDialog):
|
class TagLimit(QDialog):
|
||||||
def __init__(self, mw, parent):
|
def __init__(self, mw: AnkiQt, parent: CustomStudy) -> None:
|
||||||
QDialog.__init__(self, parent, Qt.Window)
|
QDialog.__init__(self, parent, Qt.Window)
|
||||||
self.tags: Union[str, List] = ""
|
self.tags: str = ""
|
||||||
|
self.tags_list: List[str] = []
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.parent: Optional[QWidget] = parent
|
self.parent: Optional[QWidget] = parent
|
||||||
self.deck = self.parent.deck
|
self.deck = self.parent.deck
|
||||||
|
@ -29,7 +32,7 @@ class TagLimit(QDialog):
|
||||||
restoreGeom(self, "tagLimit")
|
restoreGeom(self, "tagLimit")
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
def rebuildTagList(self):
|
def rebuildTagList(self) -> None:
|
||||||
usertags = self.mw.col.tags.byDeck(self.deck["id"], True)
|
usertags = self.mw.col.tags.byDeck(self.deck["id"], True)
|
||||||
yes = self.deck.get("activeTags", [])
|
yes = self.deck.get("activeTags", [])
|
||||||
no = self.deck.get("inactiveTags", [])
|
no = self.deck.get("inactiveTags", [])
|
||||||
|
@ -42,10 +45,10 @@ class TagLimit(QDialog):
|
||||||
groupedTags = []
|
groupedTags = []
|
||||||
usertags.sort()
|
usertags.sort()
|
||||||
groupedTags.append(usertags)
|
groupedTags.append(usertags)
|
||||||
self.tags = []
|
self.tags_list = []
|
||||||
for tags in groupedTags:
|
for tags in groupedTags:
|
||||||
for t in tags:
|
for t in tags:
|
||||||
self.tags.append(t)
|
self.tags_list.append(t)
|
||||||
item = QListWidgetItem(t.replace("_", " "))
|
item = QListWidgetItem(t.replace("_", " "))
|
||||||
self.dialog.activeList.addItem(item)
|
self.dialog.activeList.addItem(item)
|
||||||
if t in yesHash:
|
if t in yesHash:
|
||||||
|
@ -69,7 +72,7 @@ class TagLimit(QDialog):
|
||||||
self.tags = ""
|
self.tags = ""
|
||||||
QDialog.reject(self)
|
QDialog.reject(self)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self) -> None:
|
||||||
self.hide()
|
self.hide()
|
||||||
# gather yes/no tags
|
# gather yes/no tags
|
||||||
yes = []
|
yes = []
|
||||||
|
@ -80,12 +83,12 @@ class TagLimit(QDialog):
|
||||||
item = self.dialog.activeList.item(c)
|
item = self.dialog.activeList.item(c)
|
||||||
idx = self.dialog.activeList.indexFromItem(item)
|
idx = self.dialog.activeList.indexFromItem(item)
|
||||||
if self.dialog.activeList.selectionModel().isSelected(idx):
|
if self.dialog.activeList.selectionModel().isSelected(idx):
|
||||||
yes.append(self.tags[c])
|
yes.append(self.tags_list[c])
|
||||||
# inactive
|
# inactive
|
||||||
item = self.dialog.inactiveList.item(c)
|
item = self.dialog.inactiveList.item(c)
|
||||||
idx = self.dialog.inactiveList.indexFromItem(item)
|
idx = self.dialog.inactiveList.indexFromItem(item)
|
||||||
if self.dialog.inactiveList.selectionModel().isSelected(idx):
|
if self.dialog.inactiveList.selectionModel().isSelected(idx):
|
||||||
no.append(self.tags[c])
|
no.append(self.tags_list[c])
|
||||||
# save in the deck for future invocations
|
# save in the deck for future invocations
|
||||||
self.deck["activeTags"] = yes
|
self.deck["activeTags"] = yes
|
||||||
self.deck["inactiveTags"] = no
|
self.deck["inactiveTags"] = no
|
||||||
|
|
|
@ -78,7 +78,7 @@ class TaskManager(QObject):
|
||||||
|
|
||||||
self.run_in_background(task, wrapped_done)
|
self.run_in_background(task, wrapped_done)
|
||||||
|
|
||||||
def _on_closures_pending(self):
|
def _on_closures_pending(self) -> None:
|
||||||
"""Run any pending closures. This runs in the main thread."""
|
"""Run any pending closures. This runs in the main thread."""
|
||||||
with self._closures_lock:
|
with self._closures_lock:
|
||||||
closures = self._closures
|
closures = self._closures
|
||||||
|
|
|
@ -7,6 +7,7 @@ import requests
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.utils import platDesc, versionWithBuild
|
from anki.utils import platDesc, versionWithBuild
|
||||||
|
from aqt.main import AnkiQt
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import TR, openLink, showText, tr
|
from aqt.utils import TR, openLink, showText, tr
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ class LatestVersionFinder(QThread):
|
||||||
newMsg = pyqtSignal(dict)
|
newMsg = pyqtSignal(dict)
|
||||||
clockIsOff = pyqtSignal(float)
|
clockIsOff = pyqtSignal(float)
|
||||||
|
|
||||||
def __init__(self, main):
|
def __init__(self, main: AnkiQt) -> None:
|
||||||
QThread.__init__(self)
|
QThread.__init__(self)
|
||||||
self.main = main
|
self.main = main
|
||||||
self.config = main.pm.meta
|
self.config = main.pm.meta
|
||||||
|
|
Loading…
Reference in a new issue