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 = { defaultConf = {
# scheduling options # scheduling options
'activeDecks': [1], 'activeDecks': [1],
'topDeck': 1,
'curDeck': 1, 'curDeck': 1,
'newSpread': NEW_CARDS_DISTRIBUTE,
'collapseTime': 1200,
'timeLim': 0,
# other config # other config
'curModel': None,
'nextPos': 1, 'nextPos': 1,
'sortType': "noteFld", 'sortType': "noteFld",
'sortBackwards': False, 'sortBackwards': False,

View file

@ -9,20 +9,7 @@ from anki.lang import _
# fixmes: # fixmes:
# - make sure users can't set grad interval < 1 # - 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 = { defaultDeck = {
'newToday': [0, 0], # currentDay, count 'newToday': [0, 0], # currentDay, count
'revToday': [0, 0], 'revToday': [0, 0],
@ -32,16 +19,6 @@ defaultDeck = {
'usn': 0, '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 = { defaultConf = {
'name': _("Default"), 'name': _("Default"),
'new': { 'new': {
@ -117,15 +94,10 @@ class DeckManager(object):
return int(id) return int(id)
if not create: if not create:
return None return None
if "::" not in name: g = copy.deepcopy(defaultDeck)
# if it's a top level deck, it gets the top level config if "::" in name:
g = defaultTopConf.copy()
else:
# not top level; ensure all parents exist # not top level; ensure all parents exist
g = {}
self._ensureParents(name) self._ensureParents(name)
for (k,v) in defaultDeck.items():
g[k] = v
g['name'] = name g['name'] = name
while 1: while 1:
id = intTime(1000) id = intTime(1000)
@ -192,13 +164,6 @@ class DeckManager(object):
grp['name'] = grp['name'].replace(g['name']+ "::", grp['name'] = grp['name'].replace(g['name']+ "::",
newName + "::") newName + "::")
self.save(grp) 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 # adjust name and save
g['name'] = newName g['name'] = newName
self.save(g) self.save(g)
@ -284,16 +249,6 @@ usn=?,mod=? where id in %s""" % ids2str(cids),
# Deck selection # 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): def active(self):
"The currrently active dids." "The currrently active dids."
return self.col.conf['activeDecks'] return self.col.conf['activeDecks']
@ -307,9 +262,7 @@ usn=?,mod=? where id in %s""" % ids2str(cids),
def select(self, did): def select(self, did):
"Select a new branch." "Select a new branch."
# save the top level deck
name = self.decks[str(did)]['name'] name = self.decks[str(did)]['name']
self.col.conf['topDeck'] = self._topFor(name)
# current deck # current deck
self.col.conf['curDeck'] = did self.col.conf['curDeck'] = did
# and active decks (current + all children) # and active decks (current + all children)
@ -332,11 +285,6 @@ usn=?,mod=? where id in %s""" % ids2str(cids),
path = self.get(did)['name'].split("::") path = self.get(did)['name'].split("::")
return [self.get(x) for x in path[:-1]] 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 # Sync handling
########################################################################## ##########################################################################

View file

@ -87,17 +87,12 @@ class ModelManager(object):
def current(self): def current(self):
"Get current model." "Get current model."
try: m = self.get(self.col.conf['curModel'])
m = self.get(self.col.decks.top()['curModel']) return m or self.models.values()[0]
assert m
return m
except:
return self.models.values()[0]
def setCurrent(self, m): def setCurrent(self, m):
t = self.col.decks.top() self.col.conf['curModel'] = m['id']
t['curModel'] = m['id'] self.col.setMod()
self.col.decks.save(t)
def get(self, id): def get(self, id):
"Get model with ID, or None." "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) return self.col.getCard(id)
def _updateNewCardRatio(self): def _updateNewCardRatio(self):
if self.col.decks.top()['newSpread'] == NEW_CARDS_DISTRIBUTE: if self.col.conf['newSpread'] == NEW_CARDS_DISTRIBUTE:
if self.newCount: if self.newCount:
self.newCardModulus = ( self.newCardModulus = (
(self.newCount + self.revCount) / self.newCount) (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." "True if it's time to display a new card when distributing."
if not self.newCount: if not self.newCount:
return False return False
if self.col.decks.top()['newSpread'] == NEW_CARDS_LAST: if self.col.conf['newSpread'] == NEW_CARDS_LAST:
return False return False
elif self.col.decks.top()['newSpread'] == NEW_CARDS_FIRST: elif self.col.conf['newSpread'] == NEW_CARDS_FIRST:
return True return True
elif self.newCardModulus: elif self.newCardModulus:
return self.reps and self.reps % self.newCardModulus == 0 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(): if self._fillLrn():
cutoff = time.time() cutoff = time.time()
if collapse: if collapse:
cutoff += self.col.decks.top()['collapseTime'] cutoff += self.col.conf['collapseTime']
if self._lrnQueue[0][0] < cutoff: if self._lrnQueue[0][0] < cutoff:
id = heappop(self._lrnQueue)[1] id = heappop(self._lrnQueue)[1]
card = self.col.getCard(id) card = self.col.getCard(id)
@ -467,7 +467,7 @@ where queue = 1 and type = 2
return self.col.db.scalar( return self.col.db.scalar(
"select 1 from cards where did = ? and queue = 1 " "select 1 from cards where did = ? and queue = 1 "
"and due < ? limit 1", "and due < ? limit 1",
did, intTime() + self.col.decks.top()['collapseTime']) did, intTime() + self.col.conf['collapseTime'])
# Reviews # Reviews
########################################################################## ##########################################################################

View file

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

View file

@ -17,23 +17,19 @@ def test_basic():
# we start with the default deck selected # we start with the default deck selected
assert deck.decks.selected() == 1 assert deck.decks.selected() == 1
assert deck.decks.active() == [1] assert deck.decks.active() == [1]
assert deck.decks.top()['id'] == 1
# we can select a different deck # we can select a different deck
deck.decks.select(parentId) deck.decks.select(parentId)
assert deck.decks.selected() == parentId assert deck.decks.selected() == parentId
assert deck.decks.active() == [parentId] assert deck.decks.active() == [parentId]
assert deck.decks.top()['id'] == parentId
# let's create a child # let's create a child
childId = deck.decks.id("new deck::child") childId = deck.decks.id("new deck::child")
# it should have been added to the active list # it should have been added to the active list
assert deck.decks.selected() == parentId assert deck.decks.selected() == parentId
assert deck.decks.active() == [parentId, childId] assert deck.decks.active() == [parentId, childId]
assert deck.decks.top()['id'] == parentId
# we can select the child individually too # we can select the child individually too
deck.decks.select(childId) deck.decks.select(childId)
assert deck.decks.selected() == childId assert deck.decks.selected() == childId
assert deck.decks.active() == [childId] assert deck.decks.active() == [childId]
assert deck.decks.top()['id'] == parentId
def test_remove(): def test_remove():
deck = getEmptyDeck() deck = getEmptyDeck()
@ -83,14 +79,3 @@ def test_rename():
d.decks.rename(d.decks.get(id), "yo") d.decks.rename(d.decks.get(id), "yo")
for n in "yo", "yo::two", "yo::two::three": for n in "yo", "yo::two", "yo::two::three":
assert n in d.decks.allNames() 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) @nose.with_setup(setup_modified)
def test_conf(): def test_conf():
test_sync() test_sync()
assert deck2.conf['topDeck'] == 1 assert deck2.conf['curDeck'] == 1
deck1.conf['topDeck'] = 2 deck1.conf['curDeck'] = 2
deck1.setMod() deck1.setMod()
deck1.save() deck1.save()
assert client.sync() == "success" assert client.sync() == "success"
assert deck2.conf['topDeck'] == 2 assert deck2.conf['curDeck'] == 2
@nose.with_setup(setup_modified) @nose.with_setup(setup_modified)
def test_threeway(): def test_threeway():