mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Merge pull request #408 from ErezVolk/add-tags-on-update
Add an option to add a set of tags to notes updated on import
This commit is contained in:
commit
5edf901c16
5 changed files with 138 additions and 1 deletions
|
@ -18,7 +18,7 @@ support site, it would be great if you could add your name below as well.
|
||||||
|
|
||||||
********************
|
********************
|
||||||
|
|
||||||
- Sample Name
|
Erez Volk <erez.volk@gmail.com>
|
||||||
|
|
||||||
********************
|
********************
|
||||||
|
|
||||||
|
|
|
@ -64,11 +64,13 @@ class NoteImporter(Importer):
|
||||||
allowHTML = False
|
allowHTML = False
|
||||||
importMode = 0
|
importMode = 0
|
||||||
mapping: Optional[List[str]]
|
mapping: Optional[List[str]]
|
||||||
|
tagModified: Optional[str]
|
||||||
|
|
||||||
def __init__(self, col: _Collection, file: str) -> None:
|
def __init__(self, col: _Collection, file: str) -> None:
|
||||||
Importer.__init__(self, col, file)
|
Importer.__init__(self, col, file)
|
||||||
self.model = col.models.current()
|
self.model = col.models.current()
|
||||||
self.mapping = None
|
self.mapping = None
|
||||||
|
self.tagModified = None
|
||||||
self._tagsMapped = False
|
self._tagsMapped = False
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
|
@ -271,6 +273,13 @@ content in the text file to the correct fields."""
|
||||||
self.col.tags.register(n.tags)
|
self.col.tags.register(n.tags)
|
||||||
tags = self.col.tags.join(n.tags)
|
tags = self.col.tags.join(n.tags)
|
||||||
return [intTime(), self.col.usn(), n.fieldsStr, tags, id, n.fieldsStr, tags]
|
return [intTime(), self.col.usn(), n.fieldsStr, tags, id, n.fieldsStr, tags]
|
||||||
|
elif self.tagModified:
|
||||||
|
tags = self.col.db.scalar("select tags from notes where id = ?", id)
|
||||||
|
tagList = self.col.tags.split(tags) + self.tagModified.split()
|
||||||
|
tagList = self.col.tags.canonify(tagList)
|
||||||
|
self.col.tags.register(tagList)
|
||||||
|
tags = self.col.tags.join(tagList)
|
||||||
|
return [intTime(), self.col.usn(), n.fieldsStr, tags, id, n.fieldsStr]
|
||||||
else:
|
else:
|
||||||
return [intTime(), self.col.usn(), n.fieldsStr, id, n.fieldsStr]
|
return [intTime(), self.col.usn(), n.fieldsStr, id, n.fieldsStr]
|
||||||
|
|
||||||
|
@ -283,6 +292,13 @@ update notes set mod = ?, usn = ?, flds = ?, tags = ?
|
||||||
where id = ? and (flds != ? or tags != ?)""",
|
where id = ? and (flds != ? or tags != ?)""",
|
||||||
rows,
|
rows,
|
||||||
)
|
)
|
||||||
|
elif self.tagModified:
|
||||||
|
self.col.db.executemany(
|
||||||
|
"""
|
||||||
|
update notes set mod = ?, usn = ?, flds = ?, tags = ?
|
||||||
|
where id = ? and flds != ?""",
|
||||||
|
rows,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.col.db.executemany(
|
self.col.db.executemany(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
from anki.importing import (
|
from anki.importing import (
|
||||||
Anki2Importer,
|
Anki2Importer,
|
||||||
|
@ -194,6 +195,100 @@ def test_csv2():
|
||||||
deck.close()
|
deck.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_tsv_tag_modified():
|
||||||
|
deck = getEmptyCol()
|
||||||
|
mm = deck.models
|
||||||
|
m = mm.current()
|
||||||
|
f = mm.newField("Top")
|
||||||
|
mm.addField(m, f)
|
||||||
|
mm.save(m)
|
||||||
|
n = deck.newNote()
|
||||||
|
n["Front"] = "1"
|
||||||
|
n["Back"] = "2"
|
||||||
|
n["Top"] = "3"
|
||||||
|
n.addTag("four")
|
||||||
|
deck.addNote(n)
|
||||||
|
|
||||||
|
with NamedTemporaryFile(mode="w") as tf:
|
||||||
|
tf.write("1\tb\tc\n")
|
||||||
|
tf.flush()
|
||||||
|
i = TextImporter(deck, tf.name)
|
||||||
|
i.initMapping()
|
||||||
|
i.tagModified = "boom"
|
||||||
|
i.run()
|
||||||
|
|
||||||
|
n.load()
|
||||||
|
assert n["Front"] == "1"
|
||||||
|
assert n["Back"] == "b"
|
||||||
|
assert n["Top"] == "c"
|
||||||
|
assert "four" in n.tags
|
||||||
|
assert "boom" in n.tags
|
||||||
|
assert len(n.tags) == 2
|
||||||
|
assert i.updateCount == 1
|
||||||
|
|
||||||
|
deck.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_tsv_tag_multiple_tags():
|
||||||
|
deck = getEmptyCol()
|
||||||
|
mm = deck.models
|
||||||
|
m = mm.current()
|
||||||
|
f = mm.newField("Top")
|
||||||
|
mm.addField(m, f)
|
||||||
|
mm.save(m)
|
||||||
|
n = deck.newNote()
|
||||||
|
n["Front"] = "1"
|
||||||
|
n["Back"] = "2"
|
||||||
|
n["Top"] = "3"
|
||||||
|
n.addTag("four")
|
||||||
|
n.addTag("five")
|
||||||
|
deck.addNote(n)
|
||||||
|
|
||||||
|
with NamedTemporaryFile(mode="w") as tf:
|
||||||
|
tf.write("1\tb\tc\n")
|
||||||
|
tf.flush()
|
||||||
|
i = TextImporter(deck, tf.name)
|
||||||
|
i.initMapping()
|
||||||
|
i.tagModified = "five six"
|
||||||
|
i.run()
|
||||||
|
|
||||||
|
n.load()
|
||||||
|
assert n["Front"] == "1"
|
||||||
|
assert n["Back"] == "b"
|
||||||
|
assert n["Top"] == "c"
|
||||||
|
assert list(sorted(n.tags)) == list(sorted(["four", "five", "six"]))
|
||||||
|
|
||||||
|
deck.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_csv_tag_only_if_modified():
|
||||||
|
deck = getEmptyCol()
|
||||||
|
mm = deck.models
|
||||||
|
m = mm.current()
|
||||||
|
f = mm.newField("Left")
|
||||||
|
mm.addField(m, f)
|
||||||
|
mm.save(m)
|
||||||
|
n = deck.newNote()
|
||||||
|
n["Front"] = "1"
|
||||||
|
n["Back"] = "2"
|
||||||
|
n["Left"] = "3"
|
||||||
|
deck.addNote(n)
|
||||||
|
|
||||||
|
with NamedTemporaryFile(mode="w") as tf:
|
||||||
|
tf.write("1,2,3\n")
|
||||||
|
tf.flush()
|
||||||
|
i = TextImporter(deck, tf.name)
|
||||||
|
i.initMapping()
|
||||||
|
i.tagModified = "right"
|
||||||
|
i.run()
|
||||||
|
|
||||||
|
n.load()
|
||||||
|
assert n.tags == []
|
||||||
|
assert i.updateCount == 0
|
||||||
|
|
||||||
|
deck.close()
|
||||||
|
|
||||||
|
|
||||||
def test_supermemo_xml_01_unicode():
|
def test_supermemo_xml_01_unicode():
|
||||||
deck = getEmptyCol()
|
deck = getEmptyCol()
|
||||||
file = str(os.path.join(testDir, "support/supermemo1.xml"))
|
file = str(os.path.join(testDir, "support/supermemo1.xml"))
|
||||||
|
|
|
@ -91,6 +91,7 @@ class ImportDialog(QDialog):
|
||||||
self.frm.autoDetect.clicked.connect(self.onDelimiter)
|
self.frm.autoDetect.clicked.connect(self.onDelimiter)
|
||||||
self.updateDelimiterButtonText()
|
self.updateDelimiterButtonText()
|
||||||
self.frm.allowHTML.setChecked(self.mw.pm.profile.get("allowHTML", True))
|
self.frm.allowHTML.setChecked(self.mw.pm.profile.get("allowHTML", True))
|
||||||
|
self.frm.importMode.currentIndexChanged.connect(self.importModeChanged)
|
||||||
self.frm.importMode.setCurrentIndex(self.mw.pm.profile.get("importMode", 1))
|
self.frm.importMode.setCurrentIndex(self.mw.pm.profile.get("importMode", 1))
|
||||||
# import button
|
# import button
|
||||||
b = QPushButton(_("Import"))
|
b = QPushButton(_("Import"))
|
||||||
|
@ -179,6 +180,9 @@ you can enter it here. Use \\t to represent tab."""
|
||||||
self.mw.pm.profile["importMode"] = self.importer.importMode
|
self.mw.pm.profile["importMode"] = self.importer.importMode
|
||||||
self.importer.allowHTML = self.frm.allowHTML.isChecked()
|
self.importer.allowHTML = self.frm.allowHTML.isChecked()
|
||||||
self.mw.pm.profile["allowHTML"] = self.importer.allowHTML
|
self.mw.pm.profile["allowHTML"] = self.importer.allowHTML
|
||||||
|
if self.frm.tagModifiedCheck.isChecked():
|
||||||
|
self.importer.tagModified = self.frm.tagModifiedTag.toPlainText()
|
||||||
|
self.mw.pm.profile["tagModified"] = self.importer.tagModified
|
||||||
did = self.deck.selectedId()
|
did = self.deck.selectedId()
|
||||||
if did != self.importer.model["did"]:
|
if did != self.importer.model["did"]:
|
||||||
self.importer.model["did"] = did
|
self.importer.model["did"] = did
|
||||||
|
@ -283,6 +287,14 @@ you can enter it here. Use \\t to represent tab."""
|
||||||
def helpRequested(self):
|
def helpRequested(self):
|
||||||
openHelp("importing")
|
openHelp("importing")
|
||||||
|
|
||||||
|
def importModeChanged(self, newImportMode):
|
||||||
|
if newImportMode == 0:
|
||||||
|
allowTagModified = True
|
||||||
|
else:
|
||||||
|
allowTagModified = False
|
||||||
|
self.frm.tagModifiedCheck.setEnabled(allowTagModified)
|
||||||
|
self.frm.tagModifiedTag.setEnabled(allowTagModified)
|
||||||
|
|
||||||
|
|
||||||
def showUnicodeWarning():
|
def showUnicodeWarning():
|
||||||
"""Shorthand to show a standard warning."""
|
"""Shorthand to show a standard warning."""
|
||||||
|
|
|
@ -77,6 +77,20 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="tagModifiedLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="tagModifiedCheck">
|
||||||
|
<property name="text">
|
||||||
|
<string>Tag modified notes:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="tagModifiedTag"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
Loading…
Reference in a new issue