mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
update fields and models diags
- field changes are now applied when user closes dialog with save button, in bulk - models diag now fetches note type and saves it as required, instead of holding on top a copy that can grow stale as changes are made in subdialogs - both dialogs now perform operations in the backend - note.model() now fetches the note type on the fly, instead of holding on to a copy that may become stale
This commit is contained in:
parent
2308b136fd
commit
25f122bf5c
7 changed files with 105 additions and 85 deletions
|
@ -360,23 +360,24 @@ class ModelManager:
|
|||
f["name"] = name
|
||||
return f
|
||||
|
||||
def addField(self, m: NoteType, field: Field) -> None:
|
||||
def addField(self, m: NoteType, field: Field, save=True) -> None:
|
||||
if m["id"]:
|
||||
self.col.modSchema(check=True)
|
||||
|
||||
m["flds"].append(field)
|
||||
|
||||
if m["id"]:
|
||||
if m["id"] and save:
|
||||
self.save(m)
|
||||
|
||||
def remField(self, m: NoteType, field: Field) -> None:
|
||||
def remField(self, m: NoteType, field: Field, save=True) -> None:
|
||||
self.col.modSchema(check=True)
|
||||
|
||||
m["flds"].remove(field)
|
||||
|
||||
self.save(m)
|
||||
if save:
|
||||
self.save(m)
|
||||
|
||||
def moveField(self, m: NoteType, field: Field, idx: int) -> None:
|
||||
def moveField(self, m: NoteType, field: Field, idx: int, save=True) -> None:
|
||||
self.col.modSchema(check=True)
|
||||
oldidx = m["flds"].index(field)
|
||||
if oldidx == idx:
|
||||
|
@ -385,14 +386,16 @@ class ModelManager:
|
|||
m["flds"].remove(field)
|
||||
m["flds"].insert(idx, field)
|
||||
|
||||
self.save(m)
|
||||
if save:
|
||||
self.save(m)
|
||||
|
||||
def renameField(self, m: NoteType, field: Field, newName: str) -> None:
|
||||
def renameField(self, m: NoteType, field: Field, newName: str, save=True) -> None:
|
||||
assert field in m["flds"]
|
||||
|
||||
field["name"] = newName
|
||||
|
||||
self.save(m)
|
||||
if save:
|
||||
self.save(m)
|
||||
|
||||
# Adding & changing templates
|
||||
##################################################
|
||||
|
|
|
@ -48,9 +48,7 @@ class Note:
|
|||
self.usn = n.usn
|
||||
self.tags = list(n.tags)
|
||||
self.fields = list(n.fields)
|
||||
|
||||
self._model = self.col.models.get(self.mid)
|
||||
self._fmap = self.col.models.fieldMap(self._model)
|
||||
self._fmap = self.col.models.fieldMap(self.model())
|
||||
|
||||
# fixme: only save tags in list on save
|
||||
def to_backend_note(self) -> BackendNote:
|
||||
|
@ -66,8 +64,7 @@ class Note:
|
|||
fields=self.fields,
|
||||
)
|
||||
|
||||
def flush(self, mod=None) -> None:
|
||||
# fixme: mod unused?
|
||||
def flush(self) -> None:
|
||||
assert self.id != 0
|
||||
self.col.backend.update_note(self.to_backend_note())
|
||||
|
||||
|
@ -83,7 +80,9 @@ class Note:
|
|||
]
|
||||
|
||||
def model(self) -> Optional[NoteType]:
|
||||
return self._model
|
||||
return self.col.models.get(self.mid)
|
||||
|
||||
_model = property(model)
|
||||
|
||||
# Dict interface
|
||||
##################################################
|
||||
|
|
|
@ -341,7 +341,7 @@ class Editor:
|
|||
def _onFields(self):
|
||||
from aqt.fields import FieldDialog
|
||||
|
||||
FieldDialog(self.mw, self.note, parent=self.parentWindow)
|
||||
FieldDialog(self.mw, self.note.model(), parent=self.parentWindow)
|
||||
|
||||
def onCardLayout(self):
|
||||
self.saveNow(self._onCardLayout)
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
import aqt
|
||||
from anki.consts import *
|
||||
from anki.lang import _, ngettext
|
||||
from anki.models import NoteType
|
||||
from anki.rsbackend import TemplateError
|
||||
from aqt import AnkiQt
|
||||
from aqt.qt import *
|
||||
from aqt.utils import askUser, getOnlyText, openHelp, showWarning
|
||||
|
||||
|
||||
class FieldDialog(QDialog):
|
||||
def __init__(self, mw, note, ord=0, parent=None):
|
||||
QDialog.__init__(self, parent or mw) # , Qt.Window)
|
||||
self.mw = aqt.mw
|
||||
self.parent = parent or mw
|
||||
self.note = note
|
||||
def __init__(self, mw: AnkiQt, nt: NoteType, parent=None):
|
||||
QDialog.__init__(self, parent or mw)
|
||||
self.mw = mw.weakref()
|
||||
self.col = self.mw.col
|
||||
self.mm = self.mw.col.models
|
||||
self.model = note.model()
|
||||
self.model = nt
|
||||
self.mw.checkpoint(_("Fields"))
|
||||
self.form = aqt.forms.fields.Ui_Dialog()
|
||||
self.form.setupUi(self)
|
||||
|
@ -87,7 +87,7 @@ class FieldDialog(QDialog):
|
|||
name = self._uniqueName(_("New name:"), self.currentIdx, f["name"])
|
||||
if not name:
|
||||
return
|
||||
self.mm.renameField(self.model, f, name)
|
||||
self.mm.renameField(self.model, f, name, save=False)
|
||||
self.saveField()
|
||||
self.fillFields()
|
||||
self.form.fieldList.setCurrentRow(idx)
|
||||
|
@ -97,10 +97,8 @@ class FieldDialog(QDialog):
|
|||
if not name:
|
||||
return
|
||||
self.saveField()
|
||||
self.mw.progress.start()
|
||||
f = self.mm.newField(name)
|
||||
self.mm.addField(self.model, f)
|
||||
self.mw.progress.finish()
|
||||
self.mm.addField(self.model, f, save=False)
|
||||
self.fillFields()
|
||||
self.form.fieldList.setCurrentRow(len(self.model["flds"]) - 1)
|
||||
|
||||
|
@ -112,9 +110,7 @@ class FieldDialog(QDialog):
|
|||
if not askUser(_("Delete field from %s?") % c):
|
||||
return
|
||||
f = self.model["flds"][self.form.fieldList.currentRow()]
|
||||
self.mw.progress.start()
|
||||
self.mm.remField(self.model, f)
|
||||
self.mw.progress.finish()
|
||||
self.mm.remField(self.model, f, save=False)
|
||||
self.fillFields()
|
||||
self.form.fieldList.setCurrentRow(0)
|
||||
|
||||
|
@ -140,9 +136,7 @@ class FieldDialog(QDialog):
|
|||
def moveField(self, pos):
|
||||
self.saveField()
|
||||
f = self.model["flds"][self.currentIdx]
|
||||
self.mw.progress.start()
|
||||
self.mm.moveField(self.model, f, pos - 1)
|
||||
self.mw.progress.finish()
|
||||
self.mm.moveField(self.model, f, pos - 1, save=False)
|
||||
self.fillFields()
|
||||
self.form.fieldList.setCurrentRow(pos - 1)
|
||||
|
||||
|
@ -174,19 +168,21 @@ class FieldDialog(QDialog):
|
|||
|
||||
def accept(self):
|
||||
self.saveField()
|
||||
if self.oldSortField != self.model["sortf"]:
|
||||
self.mw.progress.start()
|
||||
self.mw.col.updateFieldCache(self.mm.nids(self.model))
|
||||
self.mw.progress.finish()
|
||||
try:
|
||||
self.mm.save(self.model)
|
||||
except TemplateError as e:
|
||||
# fixme: i18n
|
||||
showWarning("Unable to save changes: " + str(e))
|
||||
return
|
||||
|
||||
self.mw.reset()
|
||||
QDialog.accept(self)
|
||||
def save():
|
||||
self.mm.save(self.model)
|
||||
|
||||
def on_done(fut):
|
||||
try:
|
||||
fut.result()
|
||||
except TemplateError as e:
|
||||
# fixme: i18n
|
||||
showWarning("Unable to save changes: " + str(e))
|
||||
return
|
||||
self.mw.reset()
|
||||
QDialog.accept(self)
|
||||
|
||||
self.mw.taskman.with_progress(save, on_done, self)
|
||||
|
||||
def onHelp(self):
|
||||
openHelp("fields")
|
||||
|
|
|
@ -1419,7 +1419,6 @@ will be lost. Continue?"""
|
|||
print("\n")
|
||||
del note.fields
|
||||
del note._fmap
|
||||
del note._model
|
||||
pprint.pprint(note.__dict__)
|
||||
|
||||
print("\nCard:")
|
||||
|
|
|
@ -8,6 +8,7 @@ from typing import List, Optional
|
|||
import aqt.clayout
|
||||
from anki import stdmodels
|
||||
from anki.lang import _, ngettext
|
||||
from anki.models import NoteType
|
||||
from anki.rsbackend import pb
|
||||
from aqt import AnkiQt, gui_hooks
|
||||
from aqt.qt import *
|
||||
|
@ -24,11 +25,11 @@ from aqt.utils import (
|
|||
|
||||
class Models(QDialog):
|
||||
def __init__(self, mw: AnkiQt, parent=None, fromMain=False):
|
||||
self.mw = mw
|
||||
self.mw = mw.weakref()
|
||||
parent = parent or mw
|
||||
self.fromMain = fromMain
|
||||
QDialog.__init__(self, parent, Qt.Window)
|
||||
self.col = mw.col
|
||||
self.col = mw.col.weakref()
|
||||
assert self.col
|
||||
self.mm = self.col.models
|
||||
self.mw.checkpoint(_("Note Types"))
|
||||
|
@ -61,25 +62,39 @@ class Models(QDialog):
|
|||
qconnect(b.clicked, self.onCards)
|
||||
b = box.addButton(_("Options..."), t)
|
||||
qconnect(b.clicked, self.onAdvanced)
|
||||
qconnect(f.modelsList.currentRowChanged, self.modelChanged)
|
||||
qconnect(f.modelsList.itemDoubleClicked, self.onRename)
|
||||
self.updateModelsList()
|
||||
|
||||
def on_done(fut):
|
||||
self.updateModelsList(fut.result())
|
||||
|
||||
self.mw.taskman.with_progress(self.col.models.all_use_counts, on_done, self)
|
||||
f.modelsList.setCurrentRow(0)
|
||||
maybeHideClose(box)
|
||||
|
||||
def onRename(self):
|
||||
txt = getText(_("New name:"), default=self.model["name"])
|
||||
nt = self.current_notetype()
|
||||
txt = getText(_("New name:"), default=nt["name"])
|
||||
if txt[1] and txt[0]:
|
||||
self.model["name"] = txt[0]
|
||||
self.mm.save(self.model, updateReqs=False)
|
||||
self.updateModelsList()
|
||||
nt["name"] = txt[0]
|
||||
self.saveAndRefresh(nt)
|
||||
|
||||
def updateModelsList(self):
|
||||
def saveAndRefresh(self, nt: NoteType) -> None:
|
||||
def save():
|
||||
self.mm.save(nt)
|
||||
return self.col.models.all_use_counts()
|
||||
|
||||
def on_done(fut):
|
||||
self.updateModelsList(fut.result())
|
||||
|
||||
self.mw.taskman.with_progress(save, on_done, self)
|
||||
|
||||
def updateModelsList(self, notetypes):
|
||||
row = self.form.modelsList.currentRow()
|
||||
if row == -1:
|
||||
row = 0
|
||||
self.models = self.col.models.all_use_counts()
|
||||
self.form.modelsList.clear()
|
||||
|
||||
self.models = notetypes
|
||||
for m in self.models:
|
||||
mUse = m.use_count
|
||||
mUse = ngettext("%d note", "%d notes", mUse) % mUse
|
||||
|
@ -87,11 +102,9 @@ class Models(QDialog):
|
|||
self.form.modelsList.addItem(item)
|
||||
self.form.modelsList.setCurrentRow(row)
|
||||
|
||||
def modelChanged(self):
|
||||
if self.model:
|
||||
self.saveModel()
|
||||
idx = self.form.modelsList.currentRow()
|
||||
self.model = self.col.models.get(self.models[idx].id)
|
||||
def current_notetype(self) -> NoteType:
|
||||
row = self.form.modelsList.currentRow()
|
||||
return self.mm.get(self.models[row].id)
|
||||
|
||||
def onAdd(self):
|
||||
m = AddModel(self.mw, self).get()
|
||||
|
@ -99,9 +112,7 @@ class Models(QDialog):
|
|||
txt = getText(_("Name:"), default=m["name"])[0]
|
||||
if txt:
|
||||
m["name"] = txt
|
||||
self.mm.ensureNameUnique(m)
|
||||
self.mm.save(m)
|
||||
self.updateModelsList()
|
||||
self.saveAndRefresh(m)
|
||||
|
||||
def onDelete(self):
|
||||
if len(self.models) < 2:
|
||||
|
@ -114,40 +125,50 @@ class Models(QDialog):
|
|||
msg = _("Delete this unused note type?")
|
||||
if not askUser(msg, parent=self):
|
||||
return
|
||||
self.mm.rem(self.model)
|
||||
self.model = None
|
||||
self.updateModelsList()
|
||||
|
||||
self.col.modSchema(check=True)
|
||||
|
||||
nt = self.current_notetype()
|
||||
|
||||
def save():
|
||||
self.mm.rem(nt)
|
||||
return self.col.models.all_use_counts()
|
||||
|
||||
def on_done(fut):
|
||||
self.updateModelsList(fut.result())
|
||||
|
||||
self.mw.taskman.with_progress(save, on_done, self)
|
||||
|
||||
def onAdvanced(self):
|
||||
nt = self.current_notetype()
|
||||
d = QDialog(self)
|
||||
frm = aqt.forms.modelopts.Ui_Dialog()
|
||||
frm.setupUi(d)
|
||||
frm.latexsvg.setChecked(self.model.get("latexsvg", False))
|
||||
frm.latexHeader.setText(self.model["latexPre"])
|
||||
frm.latexFooter.setText(self.model["latexPost"])
|
||||
d.setWindowTitle(_("Options for %s") % self.model["name"])
|
||||
frm.latexsvg.setChecked(nt.get("latexsvg", False))
|
||||
frm.latexHeader.setText(nt["latexPre"])
|
||||
frm.latexFooter.setText(nt["latexPost"])
|
||||
d.setWindowTitle(_("Options for %s") % nt["name"])
|
||||
qconnect(frm.buttonBox.helpRequested, lambda: openHelp("latex"))
|
||||
restoreGeom(d, "modelopts")
|
||||
gui_hooks.models_advanced_will_show(d)
|
||||
d.exec_()
|
||||
saveGeom(d, "modelopts")
|
||||
self.model["latexsvg"] = frm.latexsvg.isChecked()
|
||||
self.model["latexPre"] = str(frm.latexHeader.toPlainText())
|
||||
self.model["latexPost"] = str(frm.latexFooter.toPlainText())
|
||||
|
||||
def saveModel(self):
|
||||
self.mm.save(self.model, updateReqs=False)
|
||||
nt["latexsvg"] = frm.latexsvg.isChecked()
|
||||
nt["latexPre"] = str(frm.latexHeader.toPlainText())
|
||||
nt["latexPost"] = str(frm.latexFooter.toPlainText())
|
||||
self.saveAndRefresh(nt)
|
||||
|
||||
def _tmpNote(self):
|
||||
self.mm.setCurrent(self.model)
|
||||
nt = self.current_notetype()
|
||||
self.mm.setCurrent(nt)
|
||||
n = self.col.newNote(forDeck=False)
|
||||
field_names = list(n.keys())
|
||||
for name in field_names:
|
||||
n[name] = "(" + name + ")"
|
||||
|
||||
cloze_re = re.compile(r"{{(?:[^}:]*:)*cloze:(?:[^}:]*:)*([^}]+)}}")
|
||||
q_template = self.model["tmpls"][0]["qfmt"]
|
||||
a_template = self.model["tmpls"][0]["afmt"]
|
||||
q_template = nt["tmpls"][0]["qfmt"]
|
||||
a_template = nt["tmpls"][0]["afmt"]
|
||||
|
||||
used_cloze_fields = []
|
||||
used_cloze_fields.extend(cloze_re.findall(q_template))
|
||||
|
@ -161,8 +182,7 @@ class Models(QDialog):
|
|||
def onFields(self):
|
||||
from aqt.fields import FieldDialog
|
||||
|
||||
n = self._tmpNote()
|
||||
FieldDialog(self.mw, n, parent=self)
|
||||
FieldDialog(self.mw, self.current_notetype(), parent=self)
|
||||
|
||||
def onCards(self):
|
||||
from aqt.clayout import CardLayout
|
||||
|
@ -176,7 +196,6 @@ class Models(QDialog):
|
|||
# need to flush model on change or reject
|
||||
|
||||
def reject(self):
|
||||
self.saveModel()
|
||||
self.mw.reset()
|
||||
saveGeom(self, "models")
|
||||
QDialog.reject(self)
|
||||
|
|
12
qt/mypy.ini
12
qt/mypy.ini
|
@ -8,12 +8,9 @@ warn_redundant_casts = True
|
|||
warn_unused_configs = True
|
||||
#check_untyped_defs = true
|
||||
|
||||
[mypy-aqt.forms.*]
|
||||
check_untyped_defs=false
|
||||
[mypy-aqt.tagedit]
|
||||
check_untyped_defs=true
|
||||
[mypy-aqt.mpv]
|
||||
ignore_errors=true
|
||||
|
||||
[mypy-win32file]
|
||||
ignore_missing_imports = True
|
||||
[mypy-win32pipe]
|
||||
|
@ -54,3 +51,10 @@ ignore_missing_imports = True
|
|||
ignore_missing_imports = True
|
||||
[mypy-socks]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-aqt.forms.*]
|
||||
check_untyped_defs=false
|
||||
[mypy-aqt.tagedit]
|
||||
check_untyped_defs=true
|
||||
[mypy-aqt.fields]
|
||||
check_untyped_defs=true
|
||||
|
|
Loading…
Reference in a new issue