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:
Damien Elmes 2012-10-26 01:58:46 +09:00
parent efa1b54c2e
commit 3e45c56f3a
11 changed files with 618 additions and 260 deletions

159
aqt/customstudy.py Normal file
View 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

View file

@ -44,8 +44,6 @@ class DeckBrowser(object):
self._onShared() self._onShared()
elif cmd == "import": elif cmd == "import":
self.mw.onImport() self.mw.onImport()
elif cmd == "cram":
self.mw.onCram()
elif cmd == "create": elif cmd == "create":
deck = getOnlyText(_("New deck name:")) deck = getOnlyText(_("New deck name:"))
if deck: if deck:
@ -58,9 +56,8 @@ class DeckBrowser(object):
self._collapse(arg) self._collapse(arg)
def _keyHandler(self, evt): def _keyHandler(self, evt):
# currently does nothing
key = unicode(evt.text()) key = unicode(evt.text())
if key == "f":
self.mw.onCram()
def _selDeck(self, did): def _selDeck(self, did):
self.mw.col.decks.select(did) self.mw.col.decks.select(did)
@ -85,6 +82,7 @@ body { margin: 1em; -webkit-user-select: none; }
.count { width: 6em; text-align: right; } .count { width: 6em; text-align: right; }
.collapse { color: #000; text-decoration:none; display:inline-block; .collapse { color: #000; text-decoration:none; display:inline-block;
width: 1em; } width: 1em; }
.filtered { color: #00a !important; }
""" % dict(width=_dragIndicatorBorderWidth) """ % dict(width=_dragIndicatorBorderWidth)
_body = """ _body = """
@ -179,6 +177,7 @@ where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000)
def _deckRow(self, node, depth, cnt): def _deckRow(self, node, depth, cnt):
name, did, due, lrn, new, children = node name, did, due, lrn, new, children = node
deck = self.mw.col.decks.get(did)
if did == 1 and cnt > 1 and not children: if did == 1 and cnt > 1 and not children:
# if the default deck is empty, hide it # if the default deck is empty, hide it
if not self.mw.col.db.scalar("select 1 from cards where did = 1"): 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) collapse = "<a class=collapse href='collapse:%d'>%s</a>" % (did, prefix)
else: else:
collapse = "<span class=collapse></span>" collapse = "<span class=collapse></span>"
if deck['dyn']:
extraclass = "filtered"
else:
extraclass = ""
buf += """ 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 # due counts
def nonzeroColour(cnt, colour): def nonzeroColour(cnt, colour):
if not cnt: if not cnt:
@ -311,7 +315,6 @@ where id > ?""", (self.mw.col.sched.dayCutoff-86400)*1000)
["", "shared", _("Get Shared")], ["", "shared", _("Get Shared")],
["", "create", _("Create Deck")], ["", "create", _("Create Deck")],
["Ctrl+I", "import", _("Import File")], ["Ctrl+I", "import", _("Import File")],
["F", "cram", _("Filter/Cram")],
] ]
buf = "" buf = ""
for b in links: for b in links:

View file

@ -29,67 +29,15 @@ class DeckConf(QDialog):
SIGNAL("helpRequested()"), SIGNAL("helpRequested()"),
lambda: openHelp("filtered")) lambda: openHelp("filtered"))
self.setWindowTitle(_("Options for %s") % self.deck['name']) self.setWindowTitle(_("Options for %s") % self.deck['name'])
self.setupExamples()
self.setupOrder() self.setupOrder()
self.loadConf() self.loadConf()
self.show() self.show()
if first:
if isMac or isWin:
self.form.examples.showPopup()
else:
mw.progress.timer(200, self.form.examples.showPopup, False)
self.exec_() self.exec_()
def setupOrder(self): def setupOrder(self):
import anki.consts as cs import anki.consts as cs
self.form.order.addItems(cs.dynOrderLabels().values()) 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): def loadConf(self):
f = self.form f = self.form
d = self.deck d = self.deck

View file

@ -745,6 +745,7 @@ and check the statistics for a home deck instead."""))
self.connect(m.actionDonate, s, self.onDonate) self.connect(m.actionDonate, s, self.onDonate)
self.connect(m.actionFullSync, s, self.onFullSync) self.connect(m.actionFullSync, s, self.onFullSync)
self.connect(m.actionStudyDeck, s, self.onStudyDeck) self.connect(m.actionStudyDeck, s, self.onStudyDeck)
self.connect(m.actionCreateFiltered, s, self.onCram)
self.connect(m.actionEmptyCards, s, self.onEmptyCards) self.connect(m.actionEmptyCards, s, self.onEmptyCards)
def updateTitleBar(self): def updateTitleBar(self):

View file

@ -55,8 +55,8 @@ class Overview(object):
self.mw.moveToState("deckBrowser") self.mw.moveToState("deckBrowser")
elif url == "review": elif url == "review":
openLink(aqt.appShared+"info/%s?v=%s"%(self.sid, self.sidVer)) openLink(aqt.appShared+"info/%s?v=%s"%(self.sid, self.sidVer))
elif url == "limits": elif url == "studymore":
self.onLimits() self.onStudyMore()
else: else:
openLink(url) openLink(url)
@ -65,17 +65,14 @@ class Overview(object):
key = unicode(evt.text()) key = unicode(evt.text())
if key == "o": if key == "o":
self.mw.onDeckConf() 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: if key == "r" and cram:
self.mw.col.sched.rebuildDyn() self.mw.col.sched.rebuildDyn()
self.mw.reset() self.mw.reset()
if key == "e" and cram: if key == "e" and cram:
self.mw.col.sched.emptyDyn(self.mw.col.decks.selected()) self.mw.col.sched.emptyDyn(self.mw.col.decks.selected())
self.mw.reset() self.mw.reset()
if key == "l": if key == "c" and not cram:
self.onLimits() self.onStudyMore()
# HTML # HTML
############################################################ ############################################################
@ -98,10 +95,14 @@ class Overview(object):
def _desc(self, deck): def _desc(self, deck):
if deck['dyn']: if deck['dyn']:
search, limit, order = deck['terms'][0] desc = _("""\
desc = "%s<br>%s" % ( This is a special deck for studying outside of the normal schedule.""")
_("Search: %s") % search, desc += " " + _("""\
_("Order: %s") % dynOrderLabels()[order].lower()) 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: else:
desc = deck.get("desc", "") desc = deck.get("desc", "")
if not desc: if not desc:
@ -190,11 +191,8 @@ text-align: center;
links.append(["R", "refresh", _("Rebuild")]) links.append(["R", "refresh", _("Rebuild")])
links.append(["E", "empty", _("Empty")]) links.append(["E", "empty", _("Empty")])
else: else:
if not sum(self.mw.col.sched.counts()): links.append(["C", "studymore", _("Custom Study")])
if self.mw.col.sched.newDue() or \ #links.append(["F", "cram", _("Filter/Cram")])
self.mw.col.sched.revDue():
links.append(["L", "limits", _("Study More")])
links.append(["F", "cram", _("Filter/Cram")])
buf = "" buf = ""
for b in links: for b in links:
if b[0]: if b[0]:
@ -209,22 +207,9 @@ text-align: center;
self.bottom.web.setFixedHeight(size) self.bottom.web.setFixedHeight(size)
self.bottom.web.setLinkHandler(self._linkHandler) self.bottom.web.setLinkHandler(self._linkHandler)
# Today's limits # Studying more
###################################################################### ######################################################################
def onLimits(self): def onStudyMore(self):
d = QDialog(self.mw) import aqt.customstudy
frm = aqt.forms.limits.Ui_Dialog() aqt.customstudy.CustomStudy(self.mw)
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_()

97
aqt/taglimit.py Normal file
View 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
View 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>

View file

@ -20,21 +20,21 @@
<string>Filter</string> <string>Filter</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="2" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Limit to</string> <string>Limit to</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Search</string> <string>Search</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="1" column="1">
<widget class="QSpinBox" name="limit"> <widget class="QSpinBox" name="limit">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
@ -50,29 +50,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2"> <item row="1" column="2">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>cards selected by</string> <string>cards selected by</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1" colspan="6"> <item row="0" column="1" colspan="4">
<widget class="QLineEdit" name="search"/> <widget class="QLineEdit" name="search"/>
</item> </item>
<item row="2" column="3" colspan="4"> <item row="1" column="3" colspan="2">
<widget class="QComboBox" name="order"/> <widget class="QComboBox" name="order"/>
</item> </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> </layout>
</widget> </widget>
</item> </item>

View file

@ -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>

View file

@ -104,6 +104,7 @@
<addaction name="actionFullSync"/> <addaction name="actionFullSync"/>
</widget> </widget>
<addaction name="actionStudyDeck"/> <addaction name="actionStudyDeck"/>
<addaction name="actionCreateFiltered"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="menuMaintenance"/> <addaction name="menuMaintenance"/>
<addaction name="separator"/> <addaction name="separator"/>
@ -190,7 +191,7 @@
<string>Browse &amp;&amp; Install...</string> <string>Browse &amp;&amp; Install...</string>
</property> </property>
<property name="statusTip"> <property name="statusTip">
<string></string> <string/>
</property> </property>
</action> </action>
<action name="actionFullDatabaseCheck"> <action name="actionFullDatabaseCheck">
@ -248,6 +249,14 @@
<string>Empty Cards...</string> <string>Empty Cards...</string>
</property> </property>
</action> </action>
<action name="actionCreateFiltered">
<property name="text">
<string>Create Filtered Deck...</string>
</property>
<property name="shortcut">
<string>F</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>

126
designer/taglimit.ui Normal file
View 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>