Merge pull request #543 from Arthur-Milchior/sort_according_to_path

Sort according to path
This commit is contained in:
Damien Elmes 2020-04-07 14:44:53 +10:00 committed by GitHub
commit 6ecf2ffa2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 46 deletions

View File

@ -5,7 +5,6 @@ from __future__ import annotations
import copy
import json
import operator
import unicodedata
from typing import Any, Dict, List, Optional, Set, Tuple, Union
@ -127,7 +126,7 @@ class DeckManager:
# child of an existing deck then it needs to be renamed
deck = self.get(did)
if "::" in deck["name"]:
base = deck["name"].split("::")[-1]
base = self.basename(deck["name"])
suffix = ""
while True:
# find an unused name
@ -261,15 +260,15 @@ class DeckManager:
ontoDeckName = self.get(ontoDeckDid)["name"]
if ontoDeckDid is None or ontoDeckDid == "":
if len(self._path(draggedDeckName)) > 1:
self.rename(draggedDeck, self._basename(draggedDeckName))
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"]
assert ontoDeckName.strip()
self.rename(
draggedDeck, ontoDeckName + "::" + self._basename(draggedDeckName)
draggedDeck, ontoDeckName + "::" + self.basename(draggedDeckName)
)
def _canDragAndDrop(self, draggedDeckName: str, ontoDeckName: str) -> bool:
@ -283,24 +282,44 @@ class DeckManager:
return True
def _isParent(self, parentDeckName: str, childDeckName: str) -> Any:
return self._path(childDeckName) == self._path(parentDeckName) + [
self._basename(childDeckName)
return self.path(childDeckName) == self.path(parentDeckName) + [
self.basename(childDeckName)
]
def _isAncestor(self, ancestorDeckName: str, descendantDeckName: str) -> Any:
ancestorPath = self._path(ancestorDeckName)
return ancestorPath == self._path(descendantDeckName)[0 : len(ancestorPath)]
ancestorPath = self.path(ancestorDeckName)
return ancestorPath == self.path(descendantDeckName)[0 : len(ancestorPath)]
def _path(self, name: str) -> Any:
@staticmethod
def path(name: str) -> Any:
return name.split("::")
def _basename(self, name: str) -> Any:
return self._path(name)[-1]
_path = path
@classmethod
def basename(cls, name: str) -> Any:
return cls.path(name)[-1]
_basename = basename
@classmethod
def immediate_parent_path(cls, name: str) -> Any:
return cls._path(name)[:-1]
@classmethod
def immediate_parent(cls, name: str) -> Any:
pp = cls.immediate_parent_path(name)
if pp:
return "::".join(pp)
@classmethod
def key(cls, deck: Dict[str, Any]) -> List[str]:
return cls.path(deck["name"])
def _ensureParents(self, name: str) -> Any:
"Ensure parents exist, and return name with case matching parents."
s = ""
path = self._path(name)
path = self.path(name)
if len(path) < 2:
return name
for p in path[:-1]:
@ -454,7 +473,7 @@ class DeckManager:
def _checkDeckTree(self) -> None:
decks = self.col.decks.all()
decks.sort(key=operator.itemgetter("name"))
decks.sort(key=self.key)
names: Set[str] = set()
for deck in decks:
@ -465,14 +484,14 @@ class DeckManager:
self.save(deck)
# ensure no sections are blank
if not all(deck["name"].split("::")):
if not all(self.path(deck["name"])):
self.col.log("fix deck with missing sections", deck["name"])
deck["name"] = "recovered%d" % intTime(1000)
self.save(deck)
# immediate parent must exist
if "::" in deck["name"]:
immediateParent = "::".join(deck["name"].split("::")[:-1])
immediateParent = self.immediate_parent(deck["name"])
if immediateParent not in names:
self.col.log("fix deck with missing parent", deck["name"])
self._ensureParents(deck["name"])
@ -570,14 +589,13 @@ class DeckManager:
childMap = {}
# go through all decks, sorted by name
for deck in sorted(self.all(), key=operator.itemgetter("name")):
for deck in sorted(self.all(), key=self.key):
node: Dict[int, Any] = {}
childMap[deck["id"]] = node
# add note to immediate parent
parts = deck["name"].split("::")
if len(parts) > 1:
immediateParent = "::".join(parts[:-1])
immediateParent = self.immediate_parent(deck["name"])
if immediateParent is not None:
pid = nameMap[immediateParent]["id"]
childMap[pid][deck["id"]] = node
@ -587,7 +605,7 @@ class DeckManager:
"All parents of did."
# get parent and grandparent names
parents: List[str] = []
for part in self.get(did)["name"].split("::")[:-1]:
for part in self.immediate_parent_path(self.get(did)["name"]):
if not parents:
parents.append(part)
else:
@ -605,7 +623,7 @@ class DeckManager:
"All existing parents of name"
if "::" not in name:
return []
names = name.split("::")[:-1]
names = self.immediate_parent_path(name)
head = []
parents = []

View File

@ -7,6 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple
from anki.collection import _Collection
from anki.consts import *
from anki.decks import DeckManager
from anki.importing.base import Importer
from anki.lang import _
from anki.storage import Collection
@ -257,13 +258,13 @@ class Anki2Importer(Importer):
name = g["name"]
# if there's a prefix, replace the top level deck
if self.deckPrefix:
tmpname = "::".join(name.split("::")[1:])
tmpname = "::".join(DeckManager.path(name)[1:])
name = self.deckPrefix
if tmpname:
name += "::" + tmpname
# manually create any parents so we can pull in descriptions
head = ""
for parent in name.split("::")[:-1]:
for parent in DeckManager.immediate_parent_path(name):
if head:
head += "::"
head += parent

View File

@ -14,6 +14,7 @@ import anki
from anki import hooks
from anki.cards import Card
from anki.consts import *
from anki.decks import DeckManager
from anki.schedv2 import Scheduler as V2
from anki.utils import ids2str, intTime
@ -152,18 +153,11 @@ class Scheduler(V2):
lims: Dict[str, List[int]] = {}
data = []
def parent(name):
parts = name.split("::")
if len(parts) < 2:
return None
parts = parts[:-1]
return "::".join(parts)
for deck in decks:
p = parent(deck["name"])
p = DeckManager.immediate_parent(deck["name"])
# new
nlim = self._deckNewLimitSingle(deck)
if p:
if p is not None:
nlim = min(nlim, lims[p][0])
new = self._newForDeck(deck["id"], nlim)
# learning

View File

@ -16,6 +16,7 @@ import anki # pylint: disable=unused-import
from anki import hooks
from anki.cards import Card
from anki.consts import *
from anki.decks import DeckManager
from anki.lang import _
from anki.rsbackend import FormatTimeSpanContext, SchedTimingToday
from anki.utils import ids2str, intTime
@ -239,19 +240,12 @@ order by due"""
lims: Dict[str, List[int]] = {}
data = []
def parent(name):
parts = name.split("::")
if len(parts) < 2:
return None
parts = parts[:-1]
return "::".join(parts)
childMap = self.col.decks.childMap()
for deck in decks:
p = parent(deck["name"])
p = DeckManager.immediate_parent(deck["name"])
# new
nlim = self._deckNewLimitSingle(deck)
if p:
if p is not None:
nlim = min(nlim, lims[p][0])
new = self._newForDeck(deck["id"], nlim)
# learning
@ -279,7 +273,7 @@ order by due"""
def _groupChildren(self, grps: List[List[Any]]) -> Any:
# first, split the group names into components
for g in grps:
g[0] = g[0].split("::")
g[0] = DeckManager.path(g[0])
# and sort based on those components
grps.sort(key=itemgetter(0))
# then run main function

View File

@ -34,6 +34,7 @@ from typing import Any, Dict, List, Optional, Tuple
import anki
from anki import hooks
from anki.cards import Card
from anki.decks import DeckManager
from anki.models import NoteType
from anki.notes import Note
from anki.rsbackend import TemplateReplacementList
@ -153,7 +154,7 @@ def fields_for_rendering(
fields["Tags"] = note.stringTags().strip()
fields["Type"] = card.note_type()["name"]
fields["Deck"] = col.decks.name(card.odid or card.did)
fields["Subdeck"] = fields["Deck"].split("::")[-1]
fields["Subdeck"] = DeckManager.basename(fields["Deck"])
fields["Card"] = card.template()["name"]
flag = card.userFlag()
fields["CardFlag"] = flag and f"flag{flag}" or ""

View File

@ -20,6 +20,7 @@ from anki import hooks
from anki.cards import Card
from anki.collection import _Collection
from anki.consts import *
from anki.decks import DeckManager
from anki.lang import _, ngettext
from anki.models import NoteType
from anki.notes import Note
@ -1302,7 +1303,7 @@ QTableView {{ gridline-color: {grid} }}
def addDecks(parent, decks):
for head, did, rev, lrn, new, children in decks:
name = self.mw.col.decks.get(did)["name"]
shortname = name.split("::")[-1]
shortname = DeckManager.basename(name)
if children:
subm = parent.addMenu(shortname)
subm.addItem(_("Filter"), self._filterFunc("deck", name))

View File

@ -3,6 +3,7 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import aqt
from anki.decks import DeckManager
from anki.lang import _
from aqt import gui_hooks
from aqt.qt import *
@ -51,7 +52,10 @@ class StudyDeck(QDialog):
if title:
self.setWindowTitle(title)
if not names:
names = sorted(self.mw.col.decks.allNames(dyn=dyn, force_default=False))
names = sorted(
self.mw.col.decks.allNames(dyn=dyn, force_default=False),
key=DeckManager._path,
)
self.nameFunc = None
self.origNames = names
else: