mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 07:22:23 -04:00
improve filtered decks
- add a custom study option to the deck overview. it combines the ability to increase the daily limits with the ability to create filtered decks based on presets - removed the presets from the filtered deck dialog. - moved the filter/cram button on the decks/overview screen to the tools menu - filtered decks no longer show their search terms (easily findable by clicking options), and instead show a brief explanation of how they work. - the filter by tags preset now presents a dialog like anki 1.2's active tags dialog. decks will remember their previously selected tags. - the custom study option creates a deck called "Custom Study Session", which will automatically get reused if you custom study in a different deck. you can rename it if you want to keep it. - filtered decks now show in the deck list as blue
This commit is contained in:
parent
efa1b54c2e
commit
3e45c56f3a
11 changed files with 618 additions and 260 deletions
159
aqt/customstudy.py
Normal file
159
aqt/customstudy.py
Normal file
|
@ -0,0 +1,159 @@
|
|||
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||
# -*- coding: utf-8 -*-
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
from aqt.qt import *
|
||||
import aqt
|
||||
from anki.utils import ids2str, isWin, isMac
|
||||
from aqt.utils import showInfo, showWarning, openHelp, getOnlyText, askUser
|
||||
from operator import itemgetter
|
||||
from anki.consts import *
|
||||
|
||||
RADIO_NEW = 1
|
||||
RADIO_REV = 2
|
||||
RADIO_FORGOT = 3
|
||||
RADIO_AHEAD = 4
|
||||
RADIO_RANDOM = 5
|
||||
RADIO_PREVIEW = 6
|
||||
RADIO_TAGS = 7
|
||||
|
||||
class CustomStudy(QDialog):
|
||||
def __init__(self, mw):
|
||||
QDialog.__init__(self, mw)
|
||||
self.mw = mw
|
||||
self.deck = self.mw.col.decks.current()
|
||||
self.form = f = aqt.forms.customstudy.Ui_Dialog()
|
||||
f.setupUi(self)
|
||||
self.setWindowModality(Qt.WindowModal)
|
||||
self.setupSignals()
|
||||
f.radio1.click()
|
||||
self.exec_()
|
||||
|
||||
def setupSignals(self):
|
||||
f = self.form; c = self.connect; s = SIGNAL("clicked()")
|
||||
c(f.radio1, s, lambda: self.onRadioChange(1))
|
||||
c(f.radio2, s, lambda: self.onRadioChange(2))
|
||||
c(f.radio3, s, lambda: self.onRadioChange(3))
|
||||
c(f.radio4, s, lambda: self.onRadioChange(4))
|
||||
c(f.radio5, s, lambda: self.onRadioChange(5))
|
||||
c(f.radio6, s, lambda: self.onRadioChange(6))
|
||||
c(f.radio7, s, lambda: self.onRadioChange(7))
|
||||
|
||||
def onRadioChange(self, idx):
|
||||
f = self.form; sp = f.spin
|
||||
smin = 1; smax = 9999; sval = 1
|
||||
post = _("cards")
|
||||
tit = ""
|
||||
spShow = True
|
||||
def plus(num):
|
||||
if num == 1000:
|
||||
num = "1000+"
|
||||
return "<b>"+str(num)+"</b>"
|
||||
if idx == RADIO_NEW:
|
||||
new = self.mw.col.sched.totalNewForCurrentDeck()
|
||||
self.deck['newToday']
|
||||
tit = _("New cards in deck: %s") % plus(new)
|
||||
pre = _("Increase today's new card limit by")
|
||||
sval = min(new, self.deck.get('extendNew', 10))
|
||||
smax = new
|
||||
elif idx == RADIO_REV:
|
||||
rev = self.mw.col.sched.totalRevForCurrentDeck()
|
||||
tit = _("Reviews due in deck: %s") % plus(rev)
|
||||
pre = _("Increase today's review limit by")
|
||||
sval = min(rev, self.deck.get('extendRev', 10))
|
||||
elif idx == RADIO_FORGOT:
|
||||
pre = _("Review cards forgotten in last")
|
||||
post = _("days")
|
||||
smax = 30
|
||||
elif idx == RADIO_AHEAD:
|
||||
pre = _("Review ahead by")
|
||||
post = _("days")
|
||||
elif idx == RADIO_RANDOM:
|
||||
pre = _("Select")
|
||||
post = _("cards randomly from the deck")
|
||||
sval = 100
|
||||
elif idx == RADIO_PREVIEW:
|
||||
pre = _("Preview new cards added in the last")
|
||||
post = _("days")
|
||||
sval = 1
|
||||
elif idx == RADIO_TAGS:
|
||||
tit = _("Press OK to choose tags.")
|
||||
sval = 100
|
||||
spShow = False
|
||||
pre = post = ""
|
||||
sp.setShown(spShow)
|
||||
f.title.setText(tit)
|
||||
f.title.setShown(not not tit)
|
||||
f.spin.setMinimum(smin)
|
||||
f.spin.setMaximum(smax)
|
||||
f.spin.setValue(sval)
|
||||
f.preSpin.setText(pre)
|
||||
f.postSpin.setText(post)
|
||||
self.radioIdx = idx
|
||||
|
||||
def accept(self):
|
||||
f = self.form; i = self.radioIdx; spin = f.spin.value()
|
||||
if i == RADIO_NEW:
|
||||
self.deck['extendNew'] = spin
|
||||
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:
|
||||
self.deck['extendRev'] = spin
|
||||
self.mw.col.decks.save(self.deck)
|
||||
self.mw.col.sched.extendLimits(0, spin)
|
||||
self.mw.reset()
|
||||
return QDialog.accept(self)
|
||||
elif i == RADIO_TAGS:
|
||||
tags = self._getTags()
|
||||
if not tags:
|
||||
return
|
||||
# the rest create a filtered deck
|
||||
cur = self.mw.col.decks.byName(_("Custom Study Session"))
|
||||
if cur:
|
||||
if not cur['dyn']:
|
||||
showInfo("Please rename the existing Custom Study deck first.")
|
||||
return QDialog.accept(self)
|
||||
else:
|
||||
# safe to empty
|
||||
self.mw.col.sched.emptyDyn(cur['id'])
|
||||
# reuse; don't delete as it may have children
|
||||
dyn = cur
|
||||
self.mw.col.decks.select(cur['id'])
|
||||
else:
|
||||
did = self.mw.col.decks.newDyn(_("Custom Study Session"))
|
||||
dyn = self.mw.col.decks.get(did)
|
||||
# and then set various options
|
||||
if i == RADIO_FORGOT:
|
||||
dyn['delays'] = [1]
|
||||
dyn['terms'][0] = ['rated:1:%d' % spin, 9999, DYN_RANDOM]
|
||||
dyn['resched'] = False
|
||||
elif i == RADIO_AHEAD:
|
||||
dyn['delays'] = None
|
||||
dyn['terms'][0] = ['prop:due<=%d' % spin, 9999, DYN_DUE]
|
||||
dyn['resched'] = True
|
||||
elif i == RADIO_RANDOM:
|
||||
dyn['delays'] = None
|
||||
dyn['terms'][0] = ['', spin, DYN_RANDOM]
|
||||
dyn['resched'] = True
|
||||
elif i == RADIO_PREVIEW:
|
||||
dyn['delays'] = None
|
||||
dyn['terms'][0] = ['is:new added:%s'%spin, 9999, DYN_OLDEST]
|
||||
dyn['resched'] = True
|
||||
elif i == RADIO_TAGS:
|
||||
dyn['delays'] = None
|
||||
dyn['terms'][0] = ["(is:new or is:due) "+tags, 9999, DYN_RANDOM]
|
||||
dyn['resched'] = True
|
||||
# add deck limit
|
||||
dyn['terms'][0][0] = "deck:'%s' %s " % (self.deck['name'], dyn['terms'][0][0])
|
||||
# generate cards
|
||||
if not self.mw.col.sched.rebuildDyn():
|
||||
return showWarning(_("No cards matched the criteria you provided."))
|
||||
self.mw.moveToState("overview")
|
||||
QDialog.accept(self)
|
||||
|
||||
def _getTags(self):
|
||||
from aqt.taglimit import TagLimit
|
||||
t = TagLimit(self.mw, self)
|
||||
return t.tags
|
|
@ -44,8 +44,6 @@ class DeckBrowser(object):
|
|||
self._onShared()
|
||||
elif cmd == "import":
|
||||
self.mw.onImport()
|
||||
elif cmd == "cram":
|
||||
self.mw.onCram()
|
||||
elif cmd == "create":
|
||||
deck = getOnlyText(_("New deck name:"))
|
||||
if deck:
|
||||
|
@ -58,9 +56,8 @@ class DeckBrowser(object):
|
|||
self._collapse(arg)
|
||||
|
||||
def _keyHandler(self, evt):
|
||||
# currently does nothing
|
||||
key = unicode(evt.text())
|
||||
if key == "f":
|
||||
self.mw.onCram()
|
||||
|
||||
def _selDeck(self, did):
|
||||
self.mw.col.decks.select(did)
|
||||
|
@ -85,6 +82,7 @@ body { margin: 1em; -webkit-user-select: none; }
|
|||
.count { width: 6em; text-align: right; }
|
||||
.collapse { color: #000; text-decoration:none; display:inline-block;
|
||||
width: 1em; }
|
||||
.filtered { color: #00a !important; }
|
||||
""" % dict(width=_dragIndicatorBorderWidth)
|
||||
|
||||
_body = """
|
||||
|
@ -179,6 +177,7 @@ where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000)
|
|||
|
||||
def _deckRow(self, node, depth, cnt):
|
||||
name, did, due, lrn, new, children = node
|
||||
deck = self.mw.col.decks.get(did)
|
||||
if did == 1 and cnt > 1 and not children:
|
||||
# if the default deck is empty, hide it
|
||||
if not self.mw.col.db.scalar("select 1 from cards where did = 1"):
|
||||
|
@ -204,9 +203,14 @@ where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000)
|
|||
collapse = "<a class=collapse href='collapse:%d'>%s</a>" % (did, prefix)
|
||||
else:
|
||||
collapse = "<span class=collapse></span>"
|
||||
if deck['dyn']:
|
||||
extraclass = "filtered"
|
||||
else:
|
||||
extraclass = ""
|
||||
buf += """
|
||||
<td class=decktd colspan=5>%s%s<a class=deck href='open:%d'>%s</a></td>"""% (
|
||||
indent(), collapse, did, name)
|
||||
|
||||
<td class=decktd colspan=5>%s%s<a class="deck %s" href='open:%d'>%s</a></td>"""% (
|
||||
indent(), collapse, extraclass, did, name)
|
||||
# due counts
|
||||
def nonzeroColour(cnt, colour):
|
||||
if not cnt:
|
||||
|
@ -311,7 +315,6 @@ where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000)
|
|||
["", "shared", _("Get Shared")],
|
||||
["", "create", _("Create Deck")],
|
||||
["Ctrl+I", "import", _("Import File")],
|
||||
["F", "cram", _("Filter/Cram")],
|
||||
]
|
||||
buf = ""
|
||||
for b in links:
|
||||
|
|
|
@ -29,67 +29,15 @@ class DeckConf(QDialog):
|
|||
SIGNAL("helpRequested()"),
|
||||
lambda: openHelp("filtered"))
|
||||
self.setWindowTitle(_("Options for %s") % self.deck['name'])
|
||||
self.setupExamples()
|
||||
self.setupOrder()
|
||||
self.loadConf()
|
||||
self.show()
|
||||
if first:
|
||||
if isMac or isWin:
|
||||
self.form.examples.showPopup()
|
||||
else:
|
||||
mw.progress.timer(200, self.form.examples.showPopup, False)
|
||||
self.exec_()
|
||||
|
||||
def setupOrder(self):
|
||||
import anki.consts as cs
|
||||
self.form.order.addItems(cs.dynOrderLabels().values())
|
||||
|
||||
def setupExamples(self):
|
||||
import anki.consts as cs
|
||||
f = self.form
|
||||
d = self.dynExamples = cs.dynExamples()
|
||||
for c, row in enumerate(d):
|
||||
if not row:
|
||||
f.examples.insertSeparator(c)
|
||||
else:
|
||||
f.examples.addItem(row[0])
|
||||
self.connect(f.examples, SIGNAL("activated(int)"),
|
||||
self.onExample)
|
||||
# we'll need to reset whenever something is changed
|
||||
self.ignoreChange = False
|
||||
def onChange(*args):
|
||||
if self.ignoreChange:
|
||||
return
|
||||
f.examples.setCurrentIndex(0)
|
||||
c = self.connect
|
||||
c(f.steps, SIGNAL("textEdited(QString)"), onChange)
|
||||
c(f.search, SIGNAL("textEdited(QString)"), onChange)
|
||||
c(f.order, SIGNAL("activated(int)"), onChange)
|
||||
c(f.limit, SIGNAL("valueChanged(int)"), onChange)
|
||||
c(f.stepsOn, SIGNAL("stateChanged(int)"), onChange)
|
||||
c(f.resched, SIGNAL("stateChanged(int)"), onChange)
|
||||
|
||||
def onExample(self, idx):
|
||||
if idx == 0:
|
||||
return
|
||||
p = self.dynExamples[idx][1]
|
||||
f = self.form
|
||||
self.ignoreChange = True
|
||||
search = [p['search']]
|
||||
if self.search:
|
||||
search.append(self.search)
|
||||
f.search.setText(" ".join(search))
|
||||
f.order.setCurrentIndex(p['order'])
|
||||
f.resched.setChecked(p.get("resched", True))
|
||||
if p.get("steps"):
|
||||
f.steps.setText(p['steps'])
|
||||
f.stepsOn.setChecked(True)
|
||||
else:
|
||||
f.steps.setText("1 10")
|
||||
f.stepsOn.setChecked(False)
|
||||
f.limit.setValue(1000)
|
||||
self.ignoreChange = False
|
||||
|
||||
def loadConf(self):
|
||||
f = self.form
|
||||
d = self.deck
|
||||
|
|
|
@ -745,6 +745,7 @@ and check the statistics for a home deck instead."""))
|
|||
self.connect(m.actionDonate, s, self.onDonate)
|
||||
self.connect(m.actionFullSync, s, self.onFullSync)
|
||||
self.connect(m.actionStudyDeck, s, self.onStudyDeck)
|
||||
self.connect(m.actionCreateFiltered, s, self.onCram)
|
||||
self.connect(m.actionEmptyCards, s, self.onEmptyCards)
|
||||
|
||||
def updateTitleBar(self):
|
||||
|
|
|
@ -55,8 +55,8 @@ class Overview(object):
|
|||
self.mw.moveToState("deckBrowser")
|
||||
elif url == "review":
|
||||
openLink(aqt.appShared+"info/%s?v=%s"%(self.sid, self.sidVer))
|
||||
elif url == "limits":
|
||||
self.onLimits()
|
||||
elif url == "studymore":
|
||||
self.onStudyMore()
|
||||
else:
|
||||
openLink(url)
|
||||
|
||||
|
@ -65,17 +65,14 @@ class Overview(object):
|
|||
key = unicode(evt.text())
|
||||
if key == "o":
|
||||
self.mw.onDeckConf()
|
||||
if key == "f" and not cram:
|
||||
deck = self.mw.col.decks.current()
|
||||
self.mw.onCram("'deck:%s'" % deck['name'])
|
||||
if key == "r" and cram:
|
||||
self.mw.col.sched.rebuildDyn()
|
||||
self.mw.reset()
|
||||
if key == "e" and cram:
|
||||
self.mw.col.sched.emptyDyn(self.mw.col.decks.selected())
|
||||
self.mw.reset()
|
||||
if key == "l":
|
||||
self.onLimits()
|
||||
if key == "c" and not cram:
|
||||
self.onStudyMore()
|
||||
|
||||
# HTML
|
||||
############################################################
|
||||
|
@ -98,10 +95,14 @@ class Overview(object):
|
|||
|
||||
def _desc(self, deck):
|
||||
if deck['dyn']:
|
||||
search, limit, order = deck['terms'][0]
|
||||
desc = "%s<br>%s" % (
|
||||
_("Search: %s") % search,
|
||||
_("Order: %s") % dynOrderLabels()[order].lower())
|
||||
desc = _("""\
|
||||
This is a special deck for studying outside of the normal schedule.""")
|
||||
desc += " " + _("""\
|
||||
Cards will be automatically returned to their original decks after you review \
|
||||
them.""")
|
||||
desc += " " + _("""\
|
||||
Deleting this deck from the deck list will return all remaining cards \
|
||||
to their original deck.""")
|
||||
else:
|
||||
desc = deck.get("desc", "")
|
||||
if not desc:
|
||||
|
@ -190,11 +191,8 @@ text-align: center;
|
|||
links.append(["R", "refresh", _("Rebuild")])
|
||||
links.append(["E", "empty", _("Empty")])
|
||||
else:
|
||||
if not sum(self.mw.col.sched.counts()):
|
||||
if self.mw.col.sched.newDue() or \
|
||||
self.mw.col.sched.revDue():
|
||||
links.append(["L", "limits", _("Study More")])
|
||||
links.append(["F", "cram", _("Filter/Cram")])
|
||||
links.append(["C", "studymore", _("Custom Study")])
|
||||
#links.append(["F", "cram", _("Filter/Cram")])
|
||||
buf = ""
|
||||
for b in links:
|
||||
if b[0]:
|
||||
|
@ -209,22 +207,9 @@ text-align: center;
|
|||
self.bottom.web.setFixedHeight(size)
|
||||
self.bottom.web.setLinkHandler(self._linkHandler)
|
||||
|
||||
# Today's limits
|
||||
# Studying more
|
||||
######################################################################
|
||||
|
||||
def onLimits(self):
|
||||
d = QDialog(self.mw)
|
||||
frm = aqt.forms.limits.Ui_Dialog()
|
||||
frm.setupUi(d)
|
||||
deck = self.mw.col.decks.current()
|
||||
frm.newToday.setValue(deck.get('extendNew', 10))
|
||||
frm.revToday.setValue(deck.get('extendRev', 50))
|
||||
def accept():
|
||||
n = deck['extendNew'] = frm.newToday.value()
|
||||
r = deck['extendRev'] = frm.revToday.value()
|
||||
self.mw.col.decks.save(deck)
|
||||
self.mw.col.sched.extendLimits(n, r)
|
||||
self.mw.reset()
|
||||
d.connect(frm.buttonBox, SIGNAL("accepted()"), accept)
|
||||
d.exec_()
|
||||
|
||||
def onStudyMore(self):
|
||||
import aqt.customstudy
|
||||
aqt.customstudy.CustomStudy(self.mw)
|
||||
|
|
97
aqt/taglimit.py
Normal file
97
aqt/taglimit.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
import aqt
|
||||
from aqt.qt import *
|
||||
from aqt.utils import saveGeom, restoreGeom
|
||||
|
||||
class TagLimit(QDialog):
|
||||
|
||||
def __init__(self, mw, parent):
|
||||
QDialog.__init__(self, parent, Qt.Window)
|
||||
self.mw = mw
|
||||
self.parent = parent
|
||||
self.deck = self.parent.deck
|
||||
self.dialog = aqt.forms.taglimit.Ui_Dialog()
|
||||
self.dialog.setupUi(self)
|
||||
self.rebuildTagList()
|
||||
restoreGeom(self, "tagLimit")
|
||||
self.exec_()
|
||||
|
||||
def rebuildTagList(self):
|
||||
usertags = self.mw.col.tags.all()
|
||||
yes = self.deck.get("activeTags", [])
|
||||
no = self.deck.get("inactiveTags", [])
|
||||
yesHash = {}
|
||||
noHash = {}
|
||||
for y in yes:
|
||||
yesHash[y] = True
|
||||
for n in no:
|
||||
noHash[n] = True
|
||||
groupedTags = []
|
||||
usertags.sort()
|
||||
icon = QIcon(":/icons/Anki_Fact.png")
|
||||
groupedTags.append([icon, usertags])
|
||||
self.tags = []
|
||||
for (icon, tags) in groupedTags:
|
||||
for t in tags:
|
||||
self.tags.append(t)
|
||||
item = QListWidgetItem(icon, t.replace("_", " "))
|
||||
self.dialog.activeList.addItem(item)
|
||||
if t in yesHash:
|
||||
mode = QItemSelectionModel.Select
|
||||
self.dialog.activeCheck.setChecked(True)
|
||||
else:
|
||||
mode = QItemSelectionModel.Deselect
|
||||
idx = self.dialog.activeList.indexFromItem(item)
|
||||
self.dialog.activeList.selectionModel().select(idx, mode)
|
||||
# inactive
|
||||
item = QListWidgetItem(icon, t.replace("_", " "))
|
||||
self.dialog.inactiveList.addItem(item)
|
||||
if t in noHash:
|
||||
mode = QItemSelectionModel.Select
|
||||
else:
|
||||
mode = QItemSelectionModel.Deselect
|
||||
idx = self.dialog.inactiveList.indexFromItem(item)
|
||||
self.dialog.inactiveList.selectionModel().select(idx, mode)
|
||||
|
||||
def reject(self):
|
||||
self.tags = ""
|
||||
QDialog.reject(self)
|
||||
|
||||
def accept(self):
|
||||
self.hide()
|
||||
n = 0
|
||||
# gather yes/no tags
|
||||
yes = []
|
||||
no = []
|
||||
for c in range(self.dialog.activeList.count()):
|
||||
# active
|
||||
if self.dialog.activeCheck.isChecked():
|
||||
item = self.dialog.activeList.item(c)
|
||||
idx = self.dialog.activeList.indexFromItem(item)
|
||||
if self.dialog.activeList.selectionModel().isSelected(idx):
|
||||
yes.append(self.tags[c])
|
||||
# inactive
|
||||
item = self.dialog.inactiveList.item(c)
|
||||
idx = self.dialog.inactiveList.indexFromItem(item)
|
||||
if self.dialog.inactiveList.selectionModel().isSelected(idx):
|
||||
no.append(self.tags[c])
|
||||
# save in the deck for future invocations
|
||||
self.deck['activeTags'] = yes
|
||||
self.deck['inactiveTags'] = no
|
||||
self.mw.col.decks.save(self.deck)
|
||||
# build query string
|
||||
self.tags = ""
|
||||
if yes:
|
||||
arr = []
|
||||
for req in yes:
|
||||
arr.append("tag:'%s'" % req)
|
||||
self.tags += "(" + " or ".join(arr) + ")"
|
||||
if no:
|
||||
arr = []
|
||||
for req in no:
|
||||
arr.append("-tag:'%s'" % req)
|
||||
self.tags += " " + " ".join(arr)
|
||||
saveGeom(self, "tagLimit")
|
||||
QDialog.accept(self)
|
191
designer/customstudy.ui
Normal file
191
designer/customstudy.ui
Normal file
|
@ -0,0 +1,191 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>290</width>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Custom Study</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="5" column="0">
|
||||
<widget class="QRadioButton" name="radio6">
|
||||
<property name="text">
|
||||
<string>Preview new cards</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QRadioButton" name="radio5">
|
||||
<property name="text">
|
||||
<string>Study a random selection of cards</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="radio2">
|
||||
<property name="text">
|
||||
<string>Increase today's review card limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="radio1">
|
||||
<property name="text">
|
||||
<string>Increase today's new card limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="radio3">
|
||||
<property name="text">
|
||||
<string>Review forgotten cards</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QRadioButton" name="radio4">
|
||||
<property name="text">
|
||||
<string>Review ahead</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QRadioButton" name="radio7">
|
||||
<property name="text">
|
||||
<string>Limit to particular tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="title">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="preSpin">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spin"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="postSpin">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>radio1</tabstop>
|
||||
<tabstop>radio2</tabstop>
|
||||
<tabstop>radio3</tabstop>
|
||||
<tabstop>radio4</tabstop>
|
||||
<tabstop>radio5</tabstop>
|
||||
<tabstop>radio6</tabstop>
|
||||
<tabstop>radio7</tabstop>
|
||||
<tabstop>spin</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -20,21 +20,21 @@
|
|||
<string>Filter</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Limit to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="limit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
|
@ -50,29 +50,19 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>cards selected by</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="6">
|
||||
<item row="0" column="1" colspan="4">
|
||||
<widget class="QLineEdit" name="search"/>
|
||||
</item>
|
||||
<item row="2" column="3" colspan="4">
|
||||
<item row="1" column="3" colspan="2">
|
||||
<widget class="QComboBox" name="order"/>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="6">
|
||||
<widget class="QComboBox" name="examples"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Preset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>428</width>
|
||||
<height>183</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Extend Limits</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="3">
|
||||
<widget class="QSpinBox" name="revToday">
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QSpinBox" name="newToday">
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>+</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Today's review limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>+</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Today's new card limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>To review cards before they are due, please use filter/cram.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>newToday</tabstop>
|
||||
<tabstop>revToday</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -104,6 +104,7 @@
|
|||
<addaction name="actionFullSync"/>
|
||||
</widget>
|
||||
<addaction name="actionStudyDeck"/>
|
||||
<addaction name="actionCreateFiltered"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuMaintenance"/>
|
||||
<addaction name="separator"/>
|
||||
|
@ -190,7 +191,7 @@
|
|||
<string>Browse && Install...</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string></string>
|
||||
<string/>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFullDatabaseCheck">
|
||||
|
@ -248,6 +249,14 @@
|
|||
<string>Empty Cards...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCreateFiltered">
|
||||
<property name="text">
|
||||
<string>Create Filtered Deck...</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="icons.qrc"/>
|
||||
|
|
126
designer/taglimit.ui
Normal file
126
designer/taglimit.ui
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>361</width>
|
||||
<height>394</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Selective Study</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="activeCheck">
|
||||
<property name="text">
|
||||
<string>Require one or more of these tags:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="activeList">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>2</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Select tags to exclude:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="inactiveList">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>2</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>358</x>
|
||||
<y>264</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>activeCheck</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>activeList</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>133</x>
|
||||
<y>18</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>133</x>
|
||||
<y>85</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
Loading…
Reference in a new issue