Merge branch 'drag-and-drop'

This commit is contained in:
Aaron Harsh 2012-01-15 20:56:52 -08:00
commit 1aaa81ee6f
4 changed files with 87 additions and 3 deletions

View file

@ -6,6 +6,7 @@ import simplejson, copy
from anki.utils import intTime, ids2str
from anki.consts import *
from anki.lang import _
from anki.errors import DeckRenameError
# fixmes:
# - make sure users can't set grad interval < 1
@ -161,7 +162,7 @@ class DeckManager(object):
"Rename deck prefix to NAME if not exists. Updates children."
# make sure target node doesn't already exist
if newName in self.allNames():
raise Exception("Deck exists")
raise DeckRenameError(_("That deck already exists."))
# rename children
for grp in self.all():
if grp['name'].startswith(g['name'] + "::"):
@ -174,10 +175,40 @@ class DeckManager(object):
# finally, ensure we have parents
self._ensureParents(newName)
def renameForDragAndDrop(self, draggedDeckDid, ontoDeckDid):
draggedDeck = self.get(draggedDeckDid)
draggedDeckName = draggedDeck['name']
ontoDeckName = self.get(ontoDeckDid)['name']
if ontoDeckDid == None or ontoDeckDid == '':
if len(self._path(draggedDeckName)) > 1:
self.rename(draggedDeck, self._basename(draggedDeckName))
elif self._canDragAndDrop(draggedDeckName, ontoDeckName):
draggedDeck = self.get(draggedDeckDid)
draggedDeckName = draggedDeck['name']
ontoDeckName = self.get(ontoDeckDid)['name']
self.rename(draggedDeck, ontoDeckName + "::" + self._basename(draggedDeckName))
def _canDragAndDrop(self, draggedDeckName, ontoDeckName):
return draggedDeckName <> ontoDeckName \
and not self._isParent(ontoDeckName, draggedDeckName) \
and not self._isAncestor(draggedDeckName, ontoDeckName)
def _isParent(self, parentDeckName, childDeckName):
return self._path(childDeckName) == self._path(parentDeckName) + [ self._basename(childDeckName) ]
def _isAncestor(self, ancestorDeckName, descendantDeckName):
ancestorPath = self._path(ancestorDeckName)
return ancestorPath == self._path(descendantDeckName)[0:len(ancestorPath)]
def _path(self, name):
return name.split("::")
def _basename(self, name):
return self._path(name)[-1]
def _ensureParents(self, name):
path = name.split("::")
s = ""
for p in path[:-1]:
for p in self._path(name)[:-1]:
if not s:
s += p
else:

View file

@ -11,3 +11,9 @@ class AnkiError(Exception):
if self.data:
m += ": %s" % repr(self.data)
return m
class DeckRenameError(Exception):
def __init__(self, description):
self.description = description
def __str__(self):
return "Couldn't rename deck: " + description

File diff suppressed because one or more lines are too long

View file

@ -79,3 +79,49 @@ 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_renameForDragAndDrop():
d = getEmptyDeck()
def deckNames():
return [ name for name in sorted(d.decks.allNames()) if name <> u'Default' ]
languages_did = d.decks.id('Languages')
chinese_did = d.decks.id('Chinese')
hsk_did = d.decks.id('Chinese::HSK')
# Renaming also renames children
d.decks.renameForDragAndDrop(chinese_did, languages_did)
assert deckNames() == [ 'Languages', 'Languages::Chinese', 'Languages::Chinese::HSK' ]
# Dragging a deck onto itself is a no-op
d.decks.renameForDragAndDrop(languages_did, languages_did)
assert deckNames() == [ 'Languages', 'Languages::Chinese', 'Languages::Chinese::HSK' ]
# Dragging a deck onto its parent is a no-op
d.decks.renameForDragAndDrop(hsk_did, chinese_did)
assert deckNames() == [ 'Languages', 'Languages::Chinese', 'Languages::Chinese::HSK' ]
# Dragging a deck onto a descendant is a no-op
d.decks.renameForDragAndDrop(languages_did, hsk_did)
assert deckNames() == [ 'Languages', 'Languages::Chinese', 'Languages::Chinese::HSK' ]
# Can drag a grandchild onto its grandparent. It becomes a child
d.decks.renameForDragAndDrop(hsk_did, languages_did)
assert deckNames() == [ 'Languages', 'Languages::Chinese', 'Languages::HSK' ]
# Can drag a deck onto its sibling
d.decks.renameForDragAndDrop(hsk_did, chinese_did)
assert deckNames() == [ 'Languages', 'Languages::Chinese', 'Languages::Chinese::HSK' ]
# Can drag a deck back to the top level
d.decks.renameForDragAndDrop(chinese_did, None)
assert deckNames() == [ 'Chinese', 'Chinese::HSK', 'Languages' ]
# Dragging a top level deck to the top level is a no-op
d.decks.renameForDragAndDrop(chinese_did, None)
assert deckNames() == [ 'Chinese', 'Chinese::HSK', 'Languages' ]
# '' is a convenient alias for the top level DID
d.decks.renameForDragAndDrop(hsk_did, '')
assert deckNames() == [ 'Chinese', 'HSK', 'Languages' ]