drop the special config for top level decks

New/rev card mixing, collapse time and the timeboxing limit are now a
collection property. I appreciate how it could be useful to have those
settings per top-level deck in some cases, but having some settings inherited
from the top level deck makes for a confusing UI.
This commit is contained in:
Damien Elmes 2011-12-09 07:55:40 +09:00
parent 8c9c3489e5
commit 451962d4a8
7 changed files with 18 additions and 89 deletions

View file

@ -21,9 +21,12 @@ import anki.cards, anki.notes, anki.template, anki.cram, anki.find
defaultConf = {
# scheduling options
'activeDecks': [1],
'topDeck': 1,
'curDeck': 1,
'newSpread': NEW_CARDS_DISTRIBUTE,
'collapseTime': 1200,
'timeLim': 0,
# other config
'curModel': None,
'nextPos': 1,
'sortType': "noteFld",
'sortBackwards': False,

View file

@ -9,20 +9,7 @@ from anki.lang import _
# fixmes:
# - make sure users can't set grad interval < 1
# - make sure lists like new[delays] are not being shared by multiple decks
# - make sure all children have parents (create as necessary)
# - when renaming a deck, top level properties should be added or removed as
# appropriate
# notes:
# - it's difficult to enforce valid dids for models/notes/cards, as we
# may update the did locally only to have it overwritten by a more recent
# change from somewhere else. to avoid this, we allow invalid did
# references, and treat any invalid dids as the default deck.
# - deletions of deck config force a full sync
# these are a cache of the current day's reviews. they may be wrong after a
# sync merge if someone reviewed from two locations
defaultDeck = {
'newToday': [0, 0], # currentDay, count
'revToday': [0, 0],
@ -32,16 +19,6 @@ defaultDeck = {
'usn': 0,
}
# configuration only available to top level decks
defaultTopConf = {
'newSpread': NEW_CARDS_DISTRIBUTE,
'collapseTime': 1200,
'repLim': 0,
'timeLim': 600,
'curModel': None,
}
# configuration available to all decks
defaultConf = {
'name': _("Default"),
'new': {
@ -117,15 +94,10 @@ class DeckManager(object):
return int(id)
if not create:
return None
if "::" not in name:
# if it's a top level deck, it gets the top level config
g = defaultTopConf.copy()
else:
g = copy.deepcopy(defaultDeck)
if "::" in name:
# not top level; ensure all parents exist
g = {}
self._ensureParents(name)
for (k,v) in defaultDeck.items():
g[k] = v
g['name'] = name
while 1:
id = intTime(1000)
@ -192,13 +164,6 @@ class DeckManager(object):
grp['name'] = grp['name'].replace(g['name']+ "::",
newName + "::")
self.save(grp)
# adjust top level conf
if "::" in newName and "::" not in g['name']:
for k in defaultTopConf.keys():
del g[k]
elif "::" not in newName and "::" in g['name']:
for k,v in defaultTopConf.items():
g[k] = v
# adjust name and save
g['name'] = newName
self.save(g)
@ -284,16 +249,6 @@ usn=?,mod=? where id in %s""" % ids2str(cids),
# Deck selection
#############################################################
def top(self):
"The current top level deck as an object."
g = self.get(self.col.conf['topDeck'])
return g
def topIds(self):
"All dids from top level."
t = self.top()
return [t['id']] + [a[1] for a in self.children(t['id'])]
def active(self):
"The currrently active dids."
return self.col.conf['activeDecks']
@ -307,9 +262,7 @@ usn=?,mod=? where id in %s""" % ids2str(cids),
def select(self, did):
"Select a new branch."
# save the top level deck
name = self.decks[str(did)]['name']
self.col.conf['topDeck'] = self._topFor(name)
# current deck
self.col.conf['curDeck'] = did
# and active decks (current + all children)
@ -332,11 +285,6 @@ usn=?,mod=? where id in %s""" % ids2str(cids),
path = self.get(did)['name'].split("::")
return [self.get(x) for x in path[:-1]]
def _topFor(self, name):
"The top level did for NAME."
path = name.split("::")
return self.id(path[0])
# Sync handling
##########################################################################

View file

@ -87,17 +87,12 @@ class ModelManager(object):
def current(self):
"Get current model."
try:
m = self.get(self.col.decks.top()['curModel'])
assert m
return m
except:
return self.models.values()[0]
m = self.get(self.col.conf['curModel'])
return m or self.models.values()[0]
def setCurrent(self, m):
t = self.col.decks.top()
t['curModel'] = m['id']
self.col.decks.save(t)
self.col.conf['curModel'] = m['id']
self.col.setMod()
def get(self, id):
"Get model with ID, or None."

View file

@ -276,7 +276,7 @@ select id, due from cards where did = ? and queue = 0 limit ?""", did, lim)
return self.col.getCard(id)
def _updateNewCardRatio(self):
if self.col.decks.top()['newSpread'] == NEW_CARDS_DISTRIBUTE:
if self.col.conf['newSpread'] == NEW_CARDS_DISTRIBUTE:
if self.newCount:
self.newCardModulus = (
(self.newCount + self.revCount) / self.newCount)
@ -290,9 +290,9 @@ select id, due from cards where did = ? and queue = 0 limit ?""", did, lim)
"True if it's time to display a new card when distributing."
if not self.newCount:
return False
if self.col.decks.top()['newSpread'] == NEW_CARDS_LAST:
if self.col.conf['newSpread'] == NEW_CARDS_LAST:
return False
elif self.col.decks.top()['newSpread'] == NEW_CARDS_FIRST:
elif self.col.conf['newSpread'] == NEW_CARDS_FIRST:
return True
elif self.newCardModulus:
return self.reps and self.reps % self.newCardModulus == 0
@ -352,7 +352,7 @@ limit %d""" % (self._deckLimit(), self.reportLimit), lim=self.dayCutoff)
if self._fillLrn():
cutoff = time.time()
if collapse:
cutoff += self.col.decks.top()['collapseTime']
cutoff += self.col.conf['collapseTime']
if self._lrnQueue[0][0] < cutoff:
id = heappop(self._lrnQueue)[1]
card = self.col.getCard(id)
@ -467,7 +467,7 @@ where queue = 1 and type = 2
return self.col.db.scalar(
"select 1 from cards where did = ? and queue = 1 "
"and due < ? limit 1",
did, intTime() + self.col.decks.top()['collapseTime'])
did, intTime() + self.col.conf['collapseTime'])
# Reviews
##########################################################################

View file

@ -140,8 +140,6 @@ def _getColVars(db):
import anki.collection
import anki.decks
g = anki.decks.defaultDeck.copy()
for k,v in anki.decks.defaultTopConf.items():
g[k] = v
g['id'] = 1
g['name'] = _("Default")
g['conf'] = 1

View file

@ -17,23 +17,19 @@ def test_basic():
# we start with the default deck selected
assert deck.decks.selected() == 1
assert deck.decks.active() == [1]
assert deck.decks.top()['id'] == 1
# we can select a different deck
deck.decks.select(parentId)
assert deck.decks.selected() == parentId
assert deck.decks.active() == [parentId]
assert deck.decks.top()['id'] == parentId
# let's create a child
childId = deck.decks.id("new deck::child")
# it should have been added to the active list
assert deck.decks.selected() == parentId
assert deck.decks.active() == [parentId, childId]
assert deck.decks.top()['id'] == parentId
# we can select the child individually too
deck.decks.select(childId)
assert deck.decks.selected() == childId
assert deck.decks.active() == [childId]
assert deck.decks.top()['id'] == parentId
def test_remove():
deck = getEmptyDeck()
@ -83,14 +79,3 @@ def test_rename():
d.decks.rename(d.decks.get(id), "yo")
for n in "yo", "yo::two", "yo::two::three":
assert n in d.decks.allNames()
def test_topRename():
d = getEmptyDeck()
id = d.decks.id("hello::world")
# when moving to or from top level, properties should be updated
assert 'newSpread' in d.decks.get(d.decks.id("hello"))
assert 'newSpread' not in d.decks.get(d.decks.id("hello::world"))
d.decks.rename(d.decks.get(d.decks.id("hello")), "foo::bar")
assert 'newSpread' not in d.decks.get(d.decks.id("foo::bar"))
d.decks.rename(d.decks.get(d.decks.id("foo::bar")), "hello")
assert 'newSpread' in d.decks.get(d.decks.id("hello"))

View file

@ -202,12 +202,12 @@ def test_decks():
@nose.with_setup(setup_modified)
def test_conf():
test_sync()
assert deck2.conf['topDeck'] == 1
deck1.conf['topDeck'] = 2
assert deck2.conf['curDeck'] == 1
deck1.conf['curDeck'] = 2
deck1.setMod()
deck1.save()
assert client.sync() == "success"
assert deck2.conf['topDeck'] == 2
assert deck2.conf['curDeck'] == 2
@nose.with_setup(setup_modified)
def test_threeway():