anki/qt/aqt/customstudy.py

231 lines
8.5 KiB
Python
Raw Normal View History

2019-02-05 04:59:03 +01:00
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import aqt
from anki.collection import SearchNode
from anki.consts import *
2019-12-20 10:19:03 +01:00
from aqt.qt import *
from aqt.utils import TR, disable_help_button, showInfo, showWarning, tr
RADIO_NEW = 1
RADIO_REV = 2
RADIO_FORGOT = 3
RADIO_AHEAD = 4
RADIO_PREVIEW = 5
RADIO_CRAM = 6
TYPE_NEW = 0
TYPE_DUE = 1
TYPE_REVIEW = 2
TYPE_ALL = 3
2019-12-23 01:34:10 +01:00
class CustomStudy(QDialog):
2021-02-02 14:30:53 +01:00
def __init__(self, mw: aqt.AnkiQt) -> None:
QDialog.__init__(self, mw)
self.mw = mw
self.deck = self.mw.col.decks.current()
self.conf = self.mw.col.decks.get_config(self.deck["conf"])
self.form = f = aqt.forms.customstudy.Ui_Dialog()
self.created_custom_study = False
f.setupUi(self)
disable_help_button(self)
self.setWindowModality(Qt.WindowModal)
self.setupSignals()
2020-01-31 01:53:52 +01:00
f.radioNew.click()
self.exec_()
def setupSignals(self) -> None:
f = self.form
qconnect(f.radioNew.clicked, lambda: self.onRadioChange(RADIO_NEW))
qconnect(f.radioRev.clicked, lambda: self.onRadioChange(RADIO_REV))
qconnect(f.radioForgot.clicked, lambda: self.onRadioChange(RADIO_FORGOT))
qconnect(f.radioAhead.clicked, lambda: self.onRadioChange(RADIO_AHEAD))
qconnect(f.radioPreview.clicked, lambda: self.onRadioChange(RADIO_PREVIEW))
qconnect(f.radioCram.clicked, lambda: self.onRadioChange(RADIO_CRAM))
def onRadioChange(self, idx: int) -> None:
2019-12-23 01:34:10 +01:00
f = self.form
sp = f.spin
smin = 1
smax = DYN_MAX_SIZE
sval = 1
2021-03-26 04:48:26 +01:00
post = tr.custom_study_cards()
tit = ""
spShow = True
typeShow = False
2021-03-26 04:48:26 +01:00
ok = tr.custom_study_ok()
2019-12-23 01:34:10 +01:00
2021-02-02 14:30:53 +01:00
def plus(num: Union[int, str]) -> str:
if num == 1000:
num = "1000+"
return f"<b>{str(num)}</b>"
2019-12-23 01:34:10 +01:00
if idx == RADIO_NEW:
new = self.mw.col.sched.totalNewForCurrentDeck()
# get the number of new cards in deck that exceed the new cards limit
2019-12-23 01:34:10 +01:00
newUnderLearning = min(
new, self.conf["new"]["perDay"] - self.deck["newToday"][1]
)
newExceeding = min(new, new - newUnderLearning)
tit = tr(
TR.CUSTOM_STUDY_NEW_CARDS_IN_DECK_OVER_TODAY, val=plus(newExceeding)
)
2021-03-26 04:48:26 +01:00
pre = tr.custom_study_increase_todays_new_card_limit_by()
2019-12-23 01:34:10 +01:00
sval = min(new, self.deck.get("extendNew", 10))
smin = -DYN_MAX_SIZE
smax = newExceeding
elif idx == RADIO_REV:
rev = self.mw.col.sched.totalRevForCurrentDeck()
# get the number of review due in deck that exceed the review due limit
2019-12-23 01:34:10 +01:00
revUnderLearning = min(
rev, self.conf["rev"]["perDay"] - self.deck["revToday"][1]
)
revExceeding = min(rev, rev - revUnderLearning)
tit = tr(
TR.CUSTOM_STUDY_REVIEWS_DUE_IN_DECK_OVER_TODAY, val=plus(revExceeding)
)
2021-03-26 04:48:26 +01:00
pre = tr.custom_study_increase_todays_review_limit_by()
2019-12-23 01:34:10 +01:00
sval = min(rev, self.deck.get("extendRev", 10))
smin = -DYN_MAX_SIZE
smax = revExceeding
elif idx == RADIO_FORGOT:
2021-03-26 04:48:26 +01:00
pre = tr.custom_study_review_cards_forgotten_in_last()
post = tr.scheduling_days()
smax = 30
elif idx == RADIO_AHEAD:
2021-03-26 04:48:26 +01:00
pre = tr.custom_study_review_ahead_by()
post = tr.scheduling_days()
elif idx == RADIO_PREVIEW:
2021-03-26 04:48:26 +01:00
pre = tr.custom_study_preview_new_cards_added_in_the()
post = tr.scheduling_days()
sval = 1
elif idx == RADIO_CRAM:
2021-03-26 04:48:26 +01:00
pre = tr.custom_study_select()
post = tr.custom_study_cards_from_the_deck()
2019-12-23 01:34:10 +01:00
# tit = _("After pressing OK, you can choose which tags to include.")
2021-03-26 04:48:26 +01:00
ok = tr.custom_study_choose_tags()
sval = 100
typeShow = True
sp.setVisible(spShow)
f.cardType.setVisible(typeShow)
f.title.setText(tit)
f.title.setVisible(not not tit)
f.spin.setMinimum(smin)
f.spin.setMaximum(smax)
if smax > 0:
f.spin.setEnabled(True)
else:
f.spin.setEnabled(False)
f.spin.setValue(sval)
f.preSpin.setText(pre)
f.postSpin.setText(post)
f.buttonBox.button(QDialogButtonBox.Ok).setText(ok)
self.radioIdx = idx
def accept(self) -> None:
2019-12-23 01:34:10 +01:00
f = self.form
i = self.radioIdx
spin = f.spin.value()
if i == RADIO_NEW:
2019-12-23 01:34:10 +01:00
self.deck["extendNew"] = spin
self.mw.col.decks.save(self.deck)
self.mw.col.sched.extendLimits(spin, 0)
self.mw.reset()
QDialog.accept(self)
return
elif i == RADIO_REV:
2019-12-23 01:34:10 +01:00
self.deck["extendRev"] = spin
self.mw.col.decks.save(self.deck)
self.mw.col.sched.extendLimits(0, spin)
self.mw.reset()
QDialog.accept(self)
return
elif i == RADIO_CRAM:
tags = self._getTags()
# the rest create a filtered deck
2021-03-26 04:48:26 +01:00
cur = self.mw.col.decks.byName(tr.custom_study_custom_study_session())
if cur:
2019-12-23 01:34:10 +01:00
if not cur["dyn"]:
2021-03-26 04:48:26 +01:00
showInfo(tr.custom_study_must_rename_deck())
QDialog.accept(self)
return
else:
# safe to empty
2020-09-03 09:43:07 +02:00
self.mw.col.sched.empty_filtered_deck(cur["id"])
# reuse; don't delete as it may have children
dyn = cur
2019-12-23 01:34:10 +01:00
self.mw.col.decks.select(cur["id"])
else:
2021-03-26 04:48:26 +01:00
did = self.mw.col.decks.new_filtered(tr.custom_study_custom_study_session())
dyn = self.mw.col.decks.get(did)
# and then set various options
if i == RADIO_FORGOT:
search = self.mw.col.build_search_string(
SearchNode(
rated=SearchNode.Rated(days=spin, rating=SearchNode.RATING_AGAIN)
)
)
dyn["terms"][0] = [search, DYN_MAX_SIZE, DYN_RANDOM]
2019-12-23 01:34:10 +01:00
dyn["resched"] = False
elif i == RADIO_AHEAD:
search = self.mw.col.build_search_string(SearchNode(due_in_days=spin))
dyn["terms"][0] = [search, DYN_MAX_SIZE, DYN_DUE]
2019-12-23 01:34:10 +01:00
dyn["resched"] = True
elif i == RADIO_PREVIEW:
search = self.mw.col.build_search_string(
SearchNode(card_state=SearchNode.CARD_STATE_NEW),
SearchNode(added_in_days=spin),
)
dyn["terms"][0] = [search, DYN_MAX_SIZE, DYN_OLDEST]
2019-12-23 01:34:10 +01:00
dyn["resched"] = False
elif i == RADIO_CRAM:
type = f.cardType.currentRow()
if type == TYPE_NEW:
terms = self.mw.col.build_search_string(
SearchNode(card_state=SearchNode.CARD_STATE_NEW)
)
ord = DYN_ADDED
2019-12-23 01:34:10 +01:00
dyn["resched"] = True
elif type == TYPE_DUE:
terms = self.mw.col.build_search_string(
SearchNode(card_state=SearchNode.CARD_STATE_DUE)
)
ord = DYN_DUE
2019-12-23 01:34:10 +01:00
dyn["resched"] = True
elif type == TYPE_REVIEW:
terms = self.mw.col.build_search_string(
SearchNode(negated=SearchNode(card_state=SearchNode.CARD_STATE_NEW))
)
ord = DYN_RANDOM
2019-12-23 01:34:10 +01:00
dyn["resched"] = True
else:
terms = ""
ord = DYN_RANDOM
2019-12-23 01:34:10 +01:00
dyn["resched"] = False
dyn["terms"][0] = [(terms + tags).strip(), spin, ord]
# add deck limit
dyn["terms"][0][0] = self.mw.col.build_search_string(
dyn["terms"][0][0], SearchNode(deck=self.deck["name"])
)
2020-05-22 03:25:11 +02:00
self.mw.col.decks.save(dyn)
# generate cards
self.created_custom_study = True
if not self.mw.col.sched.rebuild_filtered_deck(dyn["id"]):
2021-03-26 04:48:26 +01:00
showWarning(tr.custom_study_no_cards_matched_the_criteria_you())
return
self.mw.moveToState("overview")
QDialog.accept(self)
def reject(self) -> None:
if self.created_custom_study:
# set the original deck back to current
2020-01-16 03:45:48 +01:00
self.mw.col.decks.select(self.deck["id"])
# fixme: clean up the empty custom study deck
QDialog.reject(self)
def _getTags(self) -> str:
from aqt.taglimit import TagLimit
2019-12-23 01:34:10 +01:00
2020-05-11 17:09:22 +02:00
return TagLimit(self.mw, self).tags