2019-02-05 04:59:03 +01:00
|
|
|
# Copyright: Ankitects Pty Ltd and contributors
|
2012-12-21 08:51:59 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
import aqt
|
2021-01-29 18:27:33 +01:00
|
|
|
from anki.collection import SearchTerm
|
2012-12-21 08:51:59 +01:00
|
|
|
from anki.consts import *
|
2019-12-20 10:19:03 +01:00
|
|
|
from aqt.qt import *
|
2021-01-07 05:24:49 +01:00
|
|
|
from aqt.utils import TR, disable_help_button, showInfo, showWarning, tr
|
2012-12-21 08:51:59 +01:00
|
|
|
|
|
|
|
RADIO_NEW = 1
|
|
|
|
RADIO_REV = 2
|
|
|
|
RADIO_FORGOT = 3
|
|
|
|
RADIO_AHEAD = 4
|
2013-05-27 06:50:01 +02:00
|
|
|
RADIO_PREVIEW = 5
|
|
|
|
RADIO_CRAM = 6
|
|
|
|
|
|
|
|
TYPE_NEW = 0
|
|
|
|
TYPE_DUE = 1
|
2018-07-11 12:35:08 +02:00
|
|
|
TYPE_REVIEW = 2
|
|
|
|
TYPE_ALL = 3
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2019-12-23 01:34:10 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
class CustomStudy(QDialog):
|
2020-07-13 13:25:44 +02:00
|
|
|
def __init__(self, mw) -> None:
|
2012-12-21 08:51:59 +01:00
|
|
|
QDialog.__init__(self, mw)
|
|
|
|
self.mw = mw
|
|
|
|
self.deck = self.mw.col.decks.current()
|
2020-04-03 05:54:52 +02:00
|
|
|
self.conf = self.mw.col.decks.get_config(self.deck["conf"])
|
2012-12-21 08:51:59 +01:00
|
|
|
self.form = f = aqt.forms.customstudy.Ui_Dialog()
|
2020-01-16 02:26:22 +01:00
|
|
|
self.created_custom_study = False
|
2012-12-21 08:51:59 +01:00
|
|
|
f.setupUi(self)
|
2021-01-07 05:24:49 +01:00
|
|
|
disable_help_button(self)
|
2012-12-21 08:51:59 +01:00
|
|
|
self.setWindowModality(Qt.WindowModal)
|
|
|
|
self.setupSignals()
|
2020-01-31 01:53:52 +01:00
|
|
|
f.radioNew.click()
|
2012-12-21 08:51:59 +01:00
|
|
|
self.exec_()
|
|
|
|
|
2020-07-13 13:25:44 +02:00
|
|
|
def setupSignals(self):
|
2016-05-31 10:51:40 +02:00
|
|
|
f = self.form
|
2020-05-04 05:23:08 +02:00
|
|
|
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))
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-07-13 13:25:44 +02:00
|
|
|
def onRadioChange(self, idx):
|
2019-12-23 01:34:10 +01:00
|
|
|
f = self.form
|
|
|
|
sp = f.spin
|
|
|
|
smin = 1
|
|
|
|
smax = DYN_MAX_SIZE
|
|
|
|
sval = 1
|
2020-11-17 08:42:43 +01:00
|
|
|
post = tr(TR.CUSTOM_STUDY_CARDS)
|
2012-12-21 08:51:59 +01:00
|
|
|
tit = ""
|
|
|
|
spShow = True
|
2013-05-27 06:50:01 +02:00
|
|
|
typeShow = False
|
2020-11-17 08:42:43 +01:00
|
|
|
ok = tr(TR.CUSTOM_STUDY_OK)
|
2019-12-23 01:34:10 +01:00
|
|
|
|
2020-07-13 13:25:44 +02:00
|
|
|
def plus(num):
|
|
|
|
if num == 1000:
|
2012-12-21 08:51:59 +01:00
|
|
|
num = "1000+"
|
2019-12-23 01:34:10 +01:00
|
|
|
return "<b>" + str(num) + "</b>"
|
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
if idx == RADIO_NEW:
|
|
|
|
new = self.mw.col.sched.totalNewForCurrentDeck()
|
2014-10-04 22:01:21 +02:00
|
|
|
# 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]
|
|
|
|
)
|
2014-10-04 22:01:21 +02:00
|
|
|
newExceeding = min(new, new - newUnderLearning)
|
2020-11-17 12:47:47 +01:00
|
|
|
tit = tr(
|
|
|
|
TR.CUSTOM_STUDY_NEW_CARDS_IN_DECK_OVER_TODAY, val=plus(newExceeding)
|
2020-11-17 08:42:43 +01:00
|
|
|
)
|
|
|
|
pre = tr(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))
|
2019-03-05 00:06:17 +01:00
|
|
|
smin = -DYN_MAX_SIZE
|
2014-10-04 22:01:21 +02:00
|
|
|
smax = newExceeding
|
2012-12-21 08:51:59 +01:00
|
|
|
elif idx == RADIO_REV:
|
|
|
|
rev = self.mw.col.sched.totalRevForCurrentDeck()
|
2014-10-04 22:01:21 +02:00
|
|
|
# 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]
|
|
|
|
)
|
2014-10-04 22:01:21 +02:00
|
|
|
revExceeding = min(rev, rev - revUnderLearning)
|
2020-11-17 12:47:47 +01:00
|
|
|
tit = tr(
|
|
|
|
TR.CUSTOM_STUDY_REVIEWS_DUE_IN_DECK_OVER_TODAY, val=plus(revExceeding)
|
2020-11-17 08:42:43 +01:00
|
|
|
)
|
|
|
|
pre = tr(TR.CUSTOM_STUDY_INCREASE_TODAYS_REVIEW_LIMIT_BY)
|
2019-12-23 01:34:10 +01:00
|
|
|
sval = min(rev, self.deck.get("extendRev", 10))
|
2019-03-05 00:06:17 +01:00
|
|
|
smin = -DYN_MAX_SIZE
|
2014-10-04 22:01:21 +02:00
|
|
|
smax = revExceeding
|
2012-12-21 08:51:59 +01:00
|
|
|
elif idx == RADIO_FORGOT:
|
2020-11-17 08:42:43 +01:00
|
|
|
pre = tr(TR.CUSTOM_STUDY_REVIEW_CARDS_FORGOTTEN_IN_LAST)
|
|
|
|
post = tr(TR.SCHEDULING_DAYS)
|
2012-12-21 08:51:59 +01:00
|
|
|
smax = 30
|
|
|
|
elif idx == RADIO_AHEAD:
|
2020-11-17 08:42:43 +01:00
|
|
|
pre = tr(TR.CUSTOM_STUDY_REVIEW_AHEAD_BY)
|
|
|
|
post = tr(TR.SCHEDULING_DAYS)
|
2012-12-21 08:51:59 +01:00
|
|
|
elif idx == RADIO_PREVIEW:
|
2020-11-17 08:42:43 +01:00
|
|
|
pre = tr(TR.CUSTOM_STUDY_PREVIEW_NEW_CARDS_ADDED_IN_THE)
|
|
|
|
post = tr(TR.SCHEDULING_DAYS)
|
2012-12-21 08:51:59 +01:00
|
|
|
sval = 1
|
2013-05-27 06:50:01 +02:00
|
|
|
elif idx == RADIO_CRAM:
|
2020-11-17 08:42:43 +01:00
|
|
|
pre = tr(TR.CUSTOM_STUDY_SELECT)
|
|
|
|
post = tr(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.")
|
2020-11-17 08:42:43 +01:00
|
|
|
ok = tr(TR.CUSTOM_STUDY_CHOOSE_TAGS)
|
2012-12-21 08:51:59 +01:00
|
|
|
sval = 100
|
2013-05-27 06:50:01 +02:00
|
|
|
typeShow = True
|
2013-04-15 06:46:07 +02:00
|
|
|
sp.setVisible(spShow)
|
2013-05-27 06:50:01 +02:00
|
|
|
f.cardType.setVisible(typeShow)
|
2012-12-21 08:51:59 +01:00
|
|
|
f.title.setText(tit)
|
2013-04-15 06:46:07 +02:00
|
|
|
f.title.setVisible(not not tit)
|
2012-12-21 08:51:59 +01:00
|
|
|
f.spin.setMinimum(smin)
|
|
|
|
f.spin.setMaximum(smax)
|
2020-04-10 10:26:49 +02:00
|
|
|
if smax > 0:
|
|
|
|
f.spin.setEnabled(True)
|
|
|
|
else:
|
|
|
|
f.spin.setEnabled(False)
|
2012-12-21 08:51:59 +01:00
|
|
|
f.spin.setValue(sval)
|
|
|
|
f.preSpin.setText(pre)
|
|
|
|
f.postSpin.setText(post)
|
2013-05-27 06:50:01 +02:00
|
|
|
f.buttonBox.button(QDialogButtonBox.Ok).setText(ok)
|
2012-12-21 08:51:59 +01:00
|
|
|
self.radioIdx = idx
|
|
|
|
|
|
|
|
def accept(self):
|
2019-12-23 01:34:10 +01:00
|
|
|
f = self.form
|
|
|
|
i = self.radioIdx
|
|
|
|
spin = f.spin.value()
|
2012-12-21 08:51:59 +01:00
|
|
|
if i == RADIO_NEW:
|
2019-12-23 01:34:10 +01:00
|
|
|
self.deck["extendNew"] = spin
|
2012-12-21 08:51:59 +01:00
|
|
|
self.mw.col.decks.save(self.deck)
|
|
|
|
self.mw.col.sched.extendLimits(spin, 0)
|
|
|
|
self.mw.reset()
|
|
|
|
return QDialog.accept(self)
|
|
|
|
elif i == RADIO_REV:
|
2019-12-23 01:34:10 +01:00
|
|
|
self.deck["extendRev"] = spin
|
2012-12-21 08:51:59 +01:00
|
|
|
self.mw.col.decks.save(self.deck)
|
|
|
|
self.mw.col.sched.extendLimits(0, spin)
|
|
|
|
self.mw.reset()
|
|
|
|
return QDialog.accept(self)
|
2013-05-27 06:50:01 +02:00
|
|
|
elif i == RADIO_CRAM:
|
2012-12-21 08:51:59 +01:00
|
|
|
tags = self._getTags()
|
|
|
|
# the rest create a filtered deck
|
2020-11-17 08:42:43 +01:00
|
|
|
cur = self.mw.col.decks.byName(tr(TR.CUSTOM_STUDY_CUSTOM_STUDY_SESSION))
|
2012-12-21 08:51:59 +01:00
|
|
|
if cur:
|
2019-12-23 01:34:10 +01:00
|
|
|
if not cur["dyn"]:
|
2020-08-19 17:27:14 +02:00
|
|
|
showInfo(tr(TR.CUSTOM_STUDY_MUST_RENAME_DECK))
|
2012-12-21 08:51:59 +01:00
|
|
|
return QDialog.accept(self)
|
|
|
|
else:
|
|
|
|
# safe to empty
|
2020-09-03 09:43:07 +02:00
|
|
|
self.mw.col.sched.empty_filtered_deck(cur["id"])
|
2012-12-21 08:51:59 +01:00
|
|
|
# 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"])
|
2012-12-21 08:51:59 +01:00
|
|
|
else:
|
2020-11-17 08:42:43 +01:00
|
|
|
did = self.mw.col.decks.new_filtered(
|
|
|
|
tr(TR.CUSTOM_STUDY_CUSTOM_STUDY_SESSION)
|
|
|
|
)
|
2012-12-21 08:51:59 +01:00
|
|
|
dyn = self.mw.col.decks.get(did)
|
|
|
|
# and then set various options
|
|
|
|
if i == RADIO_FORGOT:
|
2021-01-30 01:26:23 +01:00
|
|
|
search = self.mw.col.build_search_string(
|
|
|
|
SearchTerm(
|
2021-01-30 19:23:40 +01:00
|
|
|
rated=SearchTerm.Rated(days=spin, rating=SearchTerm.RATING_AGAIN)
|
2021-01-30 01:26:23 +01:00
|
|
|
)
|
|
|
|
)
|
2021-01-28 11:19:07 +01:00
|
|
|
dyn["terms"][0] = [search, DYN_MAX_SIZE, DYN_RANDOM]
|
2019-12-23 01:34:10 +01:00
|
|
|
dyn["resched"] = False
|
2012-12-21 08:51:59 +01:00
|
|
|
elif i == RADIO_AHEAD:
|
2021-01-29 18:27:33 +01:00
|
|
|
search = self.mw.col.build_search_string(SearchTerm(due_in_days=spin))
|
2021-01-28 11:19:07 +01:00
|
|
|
dyn["terms"][0] = [search, DYN_MAX_SIZE, DYN_DUE]
|
2019-12-23 01:34:10 +01:00
|
|
|
dyn["resched"] = True
|
2012-12-21 08:51:59 +01:00
|
|
|
elif i == RADIO_PREVIEW:
|
2021-01-29 18:27:33 +01:00
|
|
|
search = self.mw.col.build_search_string(
|
2021-01-30 17:56:29 +01:00
|
|
|
SearchTerm(card_state=SearchTerm.CARD_STATE_NEW),
|
2021-01-30 01:49:00 +01:00
|
|
|
SearchTerm(added_in_days=spin),
|
2021-01-29 18:27:33 +01:00
|
|
|
)
|
2021-01-28 11:19:07 +01:00
|
|
|
dyn["terms"][0] = [search, DYN_MAX_SIZE, DYN_OLDEST]
|
2019-12-23 01:34:10 +01:00
|
|
|
dyn["resched"] = False
|
2013-05-27 06:50:01 +02:00
|
|
|
elif i == RADIO_CRAM:
|
|
|
|
type = f.cardType.currentRow()
|
|
|
|
if type == TYPE_NEW:
|
2021-01-30 01:49:00 +01:00
|
|
|
terms = self.mw.col.build_search_string(
|
2021-01-30 17:56:29 +01:00
|
|
|
SearchTerm(card_state=SearchTerm.CARD_STATE_NEW)
|
2021-01-30 01:49:00 +01:00
|
|
|
)
|
2013-05-27 06:50:01 +02:00
|
|
|
ord = DYN_ADDED
|
2019-12-23 01:34:10 +01:00
|
|
|
dyn["resched"] = True
|
2013-05-27 06:50:01 +02:00
|
|
|
elif type == TYPE_DUE:
|
2021-01-30 01:49:00 +01:00
|
|
|
terms = self.mw.col.build_search_string(
|
2021-01-30 17:56:29 +01:00
|
|
|
SearchTerm(card_state=SearchTerm.CARD_STATE_DUE)
|
2021-01-30 01:49:00 +01:00
|
|
|
)
|
2013-05-27 06:50:01 +02:00
|
|
|
ord = DYN_DUE
|
2019-12-23 01:34:10 +01:00
|
|
|
dyn["resched"] = True
|
2018-07-11 12:35:08 +02:00
|
|
|
elif type == TYPE_REVIEW:
|
2021-01-29 18:27:33 +01:00
|
|
|
terms = self.mw.col.build_search_string(
|
2021-01-30 17:56:29 +01:00
|
|
|
SearchTerm(card_state=SearchTerm.CARD_STATE_NEW), negate=True
|
2021-01-29 18:27:33 +01:00
|
|
|
)
|
2018-07-11 12:35:08 +02:00
|
|
|
ord = DYN_RANDOM
|
2019-12-23 01:34:10 +01:00
|
|
|
dyn["resched"] = True
|
2013-05-27 06:50:01 +02:00
|
|
|
else:
|
|
|
|
terms = ""
|
|
|
|
ord = DYN_RANDOM
|
2019-12-23 01:34:10 +01:00
|
|
|
dyn["resched"] = False
|
|
|
|
dyn["terms"][0] = [(terms + tags).strip(), spin, ord]
|
2012-12-21 08:51:59 +01:00
|
|
|
# add deck limit
|
2021-01-29 18:27:33 +01:00
|
|
|
dyn["terms"][0][0] = self.mw.col.build_search_string(
|
|
|
|
dyn["terms"][0][0], SearchTerm(deck=self.deck["name"])
|
2021-01-28 11:19:07 +01:00
|
|
|
)
|
2020-05-22 03:25:11 +02:00
|
|
|
self.mw.col.decks.save(dyn)
|
2012-12-21 08:51:59 +01:00
|
|
|
# generate cards
|
2020-01-16 02:26:22 +01:00
|
|
|
self.created_custom_study = True
|
2020-09-03 10:02:47 +02:00
|
|
|
if not self.mw.col.sched.rebuild_filtered_deck(dyn["id"]):
|
2020-11-17 08:42:43 +01:00
|
|
|
return showWarning(tr(TR.CUSTOM_STUDY_NO_CARDS_MATCHED_THE_CRITERIA_YOU))
|
2012-12-21 08:51:59 +01:00
|
|
|
self.mw.moveToState("overview")
|
|
|
|
QDialog.accept(self)
|
|
|
|
|
2020-01-16 02:26:22 +01:00
|
|
|
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"])
|
2020-01-16 02:26:22 +01:00
|
|
|
# fixme: clean up the empty custom study deck
|
|
|
|
QDialog.reject(self)
|
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
def _getTags(self):
|
|
|
|
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
|