1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
|
# Copyright: Ankitects Pty Ltd and contributors
# -*- coding: utf-8 -*-
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from operator import itemgetter
from anki.consts import NEW_CARDS_RANDOM
from aqt.qt import *
import aqt
from aqt.utils import showInfo, showWarning, openHelp, getOnlyText, askUser, \
tooltip, saveGeom, restoreGeom
from anki.lang import _, ngettext
class DeckConf(QDialog):
def __init__(self, mw, deck):
QDialog.__init__(self, mw)
self.mw = mw
self.deck = deck
self.childDids = [
d[1] for d in self.mw.col.decks.children(self.deck['id'])]
self._origNewOrder = None
self.form = aqt.forms.dconf.Ui_Dialog()
self.form.setupUi(self)
self.mw.checkpoint(_("Options"))
self.setupCombos()
self.setupConfs()
self.setWindowModality(Qt.WindowModal)
self.form.buttonBox.helpRequested.connect(lambda: openHelp("deckoptions"))
self.form.confOpts.clicked.connect(self.confOpts)
self.form.buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked.connect(self.onRestore)
self.setWindowTitle(_("Options for %s") % self.deck['name'])
# qt doesn't size properly with altered fonts otherwise
restoreGeom(self, "deckconf", adjustSize=True)
self.show()
self.exec_()
saveGeom(self, "deckconf")
def setupCombos(self):
import anki.consts as cs
f = self.form
f.newOrder.addItems(list(cs.newCardOrderLabels().values()))
f.newOrder.currentIndexChanged.connect(self.onNewOrderChanged)
# Conf list
######################################################################
def setupConfs(self):
self.form.dconf.currentIndexChanged.connect(self.onConfChange)
self.conf = None
self.loadConfs()
def loadConfs(self):
current = self.deck['conf']
self.confList = self.mw.col.decks.allConf()
self.confList.sort(key=itemgetter('name'))
startOn = 0
self.ignoreConfChange = True
self.form.dconf.clear()
for idx, conf in enumerate(self.confList):
self.form.dconf.addItem(conf['name'])
if str(conf['id']) == str(current):
startOn = idx
self.ignoreConfChange = False
self.form.dconf.setCurrentIndex(startOn)
if self._origNewOrder is None:
self._origNewOrder = self.confList[startOn]['new']['order']
self.onConfChange(startOn)
def confOpts(self):
m = QMenu(self.mw)
a = m.addAction(_("Add"))
a.triggered.connect(self.addGroup)
a = m.addAction(_("Delete"))
a.triggered.connect(self.remGroup)
a = m.addAction(_("Rename"))
a.triggered.connect(self.renameGroup)
a = m.addAction(_("Set for all subdecks"))
a.triggered.connect(self.setChildren)
if not self.childDids:
a.setEnabled(False)
m.exec_(QCursor.pos())
def onConfChange(self, idx):
if self.ignoreConfChange:
return
if self.conf:
self.saveConf()
conf = self.confList[idx]
self.deck['conf'] = conf['id']
self.loadConf()
cnt = 0
for d in self.mw.col.decks.all():
if d['dyn']:
continue
if d['conf'] == conf['id']:
cnt += 1
if cnt > 1:
txt = _("Your changes will affect multiple decks. If you wish to "
"change only the current deck, please add a new options group first.")
else:
txt = ""
self.form.count.setText(txt)
def addGroup(self):
name = getOnlyText(_("New options group name:"))
if not name:
return
# first, save currently entered data to current conf
self.saveConf()
# then clone the conf
id = self.mw.col.decks.confId(name, cloneFrom=self.conf)
# set the deck to the new conf
self.deck['conf'] = id
# then reload the conf list
self.loadConfs()
def remGroup(self):
if int(self.conf['id']) == 1:
showInfo(_("The default configuration can't be removed."), self)
else:
self.mw.col.decks.remConf(self.conf['id'])
self.deck['conf'] = 1
self.loadConfs()
def renameGroup(self):
old = self.conf['name']
name = getOnlyText(_("New name:"), default=old)
if not name or name == old:
return
self.conf['name'] = name
self.loadConfs()
def setChildren(self):
if not askUser(
_("Set all decks below %s to this option group?") %
self.deck['name']):
return
for did in self.childDids:
deck = self.mw.col.decks.get(did)
if deck['dyn']:
continue
deck['conf'] = self.deck['conf']
self.mw.col.decks.save(deck)
tooltip(ngettext("%d deck updated.", "%d decks updated.", \
len(self.childDids)) % len(self.childDids))
# Loading
##################################################
def listToUser(self, l):
return " ".join([str(x) for x in l])
def parentLimText(self, type="new"):
# top level?
if "::" not in self.deck['name']:
return ""
lim = -1
for d in self.mw.col.decks.parents(self.deck['id']):
c = self.mw.col.decks.confForDid(d['id'])
x = c[type]['perDay']
if lim == -1:
lim = x
else:
lim = min(x, lim)
return _("(parent limit: %d)") % lim
def loadConf(self):
self.conf = self.mw.col.decks.confForDid(self.deck['id'])
# new
c = self.conf['new']
f = self.form
f.lrnSteps.setText(self.listToUser(c['delays']))
f.lrnGradInt.setValue(c['ints'][0])
f.lrnEasyInt.setValue(c['ints'][1])
f.lrnEasyInt.setValue(c['ints'][1])
f.lrnFactor.setValue(c['initialFactor']/10.0)
f.newOrder.setCurrentIndex(c['order'])
f.newPerDay.setValue(c['perDay'])
f.bury.setChecked(c.get("bury", True))
f.newplim.setText(self.parentLimText('new'))
# rev
c = self.conf['rev']
f.revPerDay.setValue(c['perDay'])
f.easyBonus.setValue(c['ease4']*100)
f.fi1.setValue(c['ivlFct']*100)
f.maxIvl.setValue(c['maxIvl'])
f.revplim.setText(self.parentLimText('rev'))
f.buryRev.setChecked(c.get("bury", True))
f.hardFactor.setValue(int(c.get("hardFactor", 1.2)*100))
if self.mw.col.schedVer() == 1:
f.hardFactor.setVisible(False)
f.hardFactorLabel.setVisible(False)
# lapse
c = self.conf['lapse']
f.lapSteps.setText(self.listToUser(c['delays']))
f.lapMult.setValue(c['mult']*100)
f.lapMinInt.setValue(c['minInt'])
f.leechThreshold.setValue(c['leechFails'])
f.leechAction.setCurrentIndex(c['leechAction'])
# general
c = self.conf
f.maxTaken.setValue(c['maxTaken'])
f.showTimer.setChecked(c.get('timer', 0))
f.autoplaySounds.setChecked(c['autoplay'])
f.replayQuestion.setChecked(c.get('replayq', True))
# description
f.desc.setPlainText(self.deck['desc'])
def onRestore(self):
self.mw.progress.start()
self.mw.col.decks.restoreToDefault(self.conf)
self.mw.progress.finish()
self.loadConf()
# New order
##################################################
def onNewOrderChanged(self, new):
old = self.conf['new']['order']
if old == new:
return
self.conf['new']['order'] = new
self.mw.progress.start()
self.mw.col.sched.resortConf(self.conf)
self.mw.progress.finish()
# Saving
##################################################
def updateList(self, conf, key, w, minSize=1):
items = str(w.text()).split(" ")
ret = []
for i in items:
if not i:
continue
try:
i = float(i)
assert i > 0
if i == int(i):
i = int(i)
ret.append(i)
except:
# invalid, don't update
showWarning(_("Steps must be numbers."))
return
if len(ret) < minSize:
showWarning(_("At least one step is required."))
return
conf[key] = ret
def saveConf(self):
# new
c = self.conf['new']
f = self.form
self.updateList(c, 'delays', f.lrnSteps)
c['ints'][0] = f.lrnGradInt.value()
c['ints'][1] = f.lrnEasyInt.value()
c['initialFactor'] = f.lrnFactor.value()*10
c['order'] = f.newOrder.currentIndex()
c['perDay'] = f.newPerDay.value()
c['bury'] = f.bury.isChecked()
if self._origNewOrder != c['order']:
# order of current deck has changed, so have to resort
if c['order'] == NEW_CARDS_RANDOM:
self.mw.col.sched.randomizeCards(self.deck['id'])
else:
self.mw.col.sched.orderCards(self.deck['id'])
# rev
c = self.conf['rev']
c['perDay'] = f.revPerDay.value()
c['ease4'] = f.easyBonus.value()/100.0
c['ivlFct'] = f.fi1.value()/100.0
c['maxIvl'] = f.maxIvl.value()
c['bury'] = f.buryRev.isChecked()
c['hardFactor'] = f.hardFactor.value()/100.0
# lapse
c = self.conf['lapse']
self.updateList(c, 'delays', f.lapSteps, minSize=0)
c['mult'] = f.lapMult.value()/100.0
c['minInt'] = f.lapMinInt.value()
c['leechFails'] = f.leechThreshold.value()
c['leechAction'] = f.leechAction.currentIndex()
# general
c = self.conf
c['maxTaken'] = f.maxTaken.value()
c['timer'] = f.showTimer.isChecked() and 1 or 0
c['autoplay'] = f.autoplaySounds.isChecked()
c['replayq'] = f.replayQuestion.isChecked()
# description
self.deck['desc'] = f.desc.toPlainText()
self.mw.col.decks.save(self.deck)
self.mw.col.decks.save(self.conf)
def reject(self):
self.accept()
def accept(self):
self.saveConf()
self.mw.reset()
QDialog.accept(self)
|