From 96818a07c7f770b6e3a014e3f4990e1640c91b8f Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Tue, 5 Aug 2014 10:42:36 -0500 Subject: [PATCH 01/10] don't allow pasting rich text into template editor --- aqt/clayout.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aqt/clayout.py b/aqt/clayout.py index aa5f423e6..f5d6b0847 100644 --- a/aqt/clayout.py +++ b/aqt/clayout.py @@ -204,6 +204,9 @@ Please create a new card type first.""")) self.tab['tform'].front.setPlainText(t['qfmt']) self.tab['tform'].css.setPlainText(self.model['css']) self.tab['tform'].back.setPlainText(t['afmt']) + self.tab['tform'].front.setAcceptRichText(False) + self.tab['tform'].css.setAcceptRichText(False) + self.tab['tform'].back.setAcceptRichText(False) self.redrawing = False def saveCard(self): From 2c05c874d7c301cf86fcc2a44c08b7f4fbb92d91 Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Tue, 5 Aug 2014 11:25:24 -0500 Subject: [PATCH 02/10] fall back to homedir on collection package export if no desktop --- aqt/exporting.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/aqt/exporting.py b/aqt/exporting.py index bc373b077..3d80266b4 100644 --- a/aqt/exporting.py +++ b/aqt/exporting.py @@ -64,13 +64,20 @@ class ExportDialog(QDialog): self.exporter.did): verbatim = True # it's a verbatim apkg export, so place on desktop instead of - # choosing file + # choosing file; use homedir if no desktop + usingHomedir = False file = os.path.join(QDesktopServices.storageLocation( QDesktopServices.DesktopLocation), "collection.apkg") + if not os.path.exists(os.path.dirname(file)): + usingHomedir = True + file = os.path.join(QDesktopServices.storageLocation( + QDesktopServices.HomeLocation), "collection.apkg") if os.path.exists(file): - if not askUser( - _("%s already exists on your desktop. Overwrite it?")% - "collection.apkg"): + if usingHomedir: + question = _("%s already exists in your home directory. Overwrite it?") + else: + question = _("%s already exists on your desktop. Overwrite it?") + if not askUser(question % "collection.apkg"): return else: verbatim = False @@ -100,7 +107,11 @@ class ExportDialog(QDialog): os.unlink(file) self.exporter.exportInto(file) if verbatim: - msg = _("A file called collection.apkg was saved on your desktop.") + if usingHomedir: + msg = _("A file called %s was saved in your home directory.") + else: + msg = _("A file called %s was saved on your desktop.") + msg = msg % "collection.apkg" period = 5000 else: period = 3000 From 5dbe267c46f9bb3166d1ccec1b597abb4423e73f Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Sun, 10 Aug 2014 13:52:09 -0500 Subject: [PATCH 03/10] add keyboard shortcut for 'manage note types' --- designer/main.ui | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/designer/main.ui b/designer/main.ui index 04f802dc1..9b9615e5c 100644 --- a/designer/main.ui +++ b/designer/main.ui @@ -46,7 +46,7 @@ 0 0 412 - 22 + 27 @@ -237,6 +237,9 @@ Manage Note Types... + + Ctrl+Shift+N + From 9bb217f1986232c5f642faec826928fc04ba1d25 Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Sun, 10 Aug 2014 14:30:08 -0500 Subject: [PATCH 04/10] reduce tab width in template editor The previous one was ridiculously wide; reduced to 30 pixels. --- aqt/clayout.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aqt/clayout.py b/aqt/clayout.py index f5d6b0847..fd2eba116 100644 --- a/aqt/clayout.py +++ b/aqt/clayout.py @@ -207,6 +207,9 @@ Please create a new card type first.""")) self.tab['tform'].front.setAcceptRichText(False) self.tab['tform'].css.setAcceptRichText(False) self.tab['tform'].back.setAcceptRichText(False) + self.tab['tform'].front.setTabStopWidth(30) + self.tab['tform'].css.setTabStopWidth(30) + self.tab['tform'].back.setTabStopWidth(30) self.redrawing = False def saveCard(self): From 1ea9fb3d4a6d4d2cf6ffdff6285cea3bbcc37cae Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Sun, 10 Aug 2014 14:32:10 -0500 Subject: [PATCH 05/10] don't allow nesting things under filtered decks when manually renaming 5e74976 fixed it for drag and drop, but realized it was still possible to do so by using the rename function manually. --- anki/decks.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/anki/decks.py b/anki/decks.py index b7940abda..b939bd5e8 100644 --- a/anki/decks.py +++ b/anki/decks.py @@ -233,6 +233,11 @@ class DeckManager(object): raise DeckRenameError(_("That deck already exists.")) # ensure we have parents newName = self._ensureParents(newName) + # make sure we're not nesting under a filtered deck + if '::' in newName: + newParent = '::'.join(newName.split('::')[:-1]) + if self.byName(newParent)['dyn']: + raise DeckRenameError(_("A filtered deck cannot have subdecks.")) # rename children for grp in self.all(): if grp['name'].startswith(g['name'] + "::"): @@ -266,8 +271,6 @@ class DeckManager(object): or self._isParent(ontoDeckName, draggedDeckName) \ or self._isAncestor(draggedDeckName, ontoDeckName): return False - elif self.byName(ontoDeckName)['dyn']: - raise DeckRenameError(_("A filtered deck cannot have subdecks.")) else: return True From a479bc7c48f9a4f393320f09a4116d8ee5ee57c8 Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Mon, 11 Aug 2014 10:31:48 -0500 Subject: [PATCH 06/10] change "discard field" to "ignore" in text importer A user pointed out that once selected it said "ignore" and that "discard" threatened that the information might be deleted. --- aqt/importing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aqt/importing.py b/aqt/importing.py index e3a42a82c..ae0130a50 100644 --- a/aqt/importing.py +++ b/aqt/importing.py @@ -34,7 +34,7 @@ class ChangeMap(QDialog): self.frm.fields.setCurrentRow(n) n += 1 self.frm.fields.addItem(QListWidgetItem(_("Map to Tags"))) - self.frm.fields.addItem(QListWidgetItem(_("Discard field"))) + self.frm.fields.addItem(QListWidgetItem(_("Ignore field"))) if not setCurrent: if current == "_tags": self.frm.fields.setCurrentRow(n) From 625d7d5a82cd088124bd3e21f4b9e50bcff8ba85 Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Mon, 11 Aug 2014 11:33:39 -0500 Subject: [PATCH 07/10] rename fields in template properly when more than one modifier used Previously something like {{type:cloze:Text}} in the template would not be renamed when the field was renamed. --- anki/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anki/models.py b/anki/models.py index 5249ee128..7f46b524b 100644 --- a/anki/models.py +++ b/anki/models.py @@ -304,10 +304,10 @@ and notes.mid = ? and cards.ord = ?""", m['id'], ord) def renameField(self, m, field, newName): self.col.modSchema() - pat = r'{{([:#^/]|[^:#/^}][^:}]*?:|)%s}}' + pat = r'{{(.*)([:#^/]|[^:#/^}][^:}]*?:|)%s}}' def wrap(txt): def repl(match): - return '{{' + match.group(1) + txt + '}}' + return '{{' + match.group(1) + match.group(2) + txt + '}}' return repl for t in m['tmpls']: for fmt in ('qfmt', 'afmt'): From b19a1707fb2251fc58a5690c6fce7cd7ea4087a3 Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Mon, 11 Aug 2014 14:32:59 -0500 Subject: [PATCH 08/10] put selection in a sensible place after deleting several cards If the last selection was at the top, the new selection will be right above the last-selected item; otherwise, it will be right below it. --- aqt/browser.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/aqt/browser.py b/aqt/browser.py index 340547865..be35a8ff7 100644 --- a/aqt/browser.py +++ b/aqt/browser.py @@ -1109,12 +1109,26 @@ where id in %s""" % ids2str(sf)) return self.mw.checkpoint(_("Delete Notes")) self.model.beginReset() - oldRow = self.form.tableView.selectionModel().currentIndex().row() + # figure out where to place the cursor after the deletion + curRow = self.form.tableView.selectionModel().currentIndex().row() + selectedRows = [i.row() for i in + self.form.tableView.selectionModel().selectedRows()] + if min(selectedRows) < curRow < max(selectedRows): + # last selection in middle; place one below last selected item + move = sum(1 for i in selectedRows if i > curRow) + newRow = curRow - move + elif max(selectedRows) <= curRow: + # last selection at bottom; place one below bottommost selection + newRow = max(selectedRows) - len(nids) + 1 + else: + # last selection at top; place one above topmost selection + newRow = min(selectedRows) - 1 self.col.remNotes(nids) self.onSearch(reset=False) if len(self.model.cards): - new = min(oldRow, len(self.model.cards) - 1) - self.model.focusedCard = self.model.cards[new] + newRow = min(newRow, len(self.model.cards) - 1) + newRow = max(newRow, 0) + self.model.focusedCard = self.model.cards[newRow] self.model.endReset() self.mw.requireReset() tooltip(_("%s deleted.") % (ngettext("%d note", "%d notes", len(nids)) % len(nids))) From 439f9b766d6699421e6264cfa1930d13005a0fdc Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Thu, 14 Aug 2014 10:51:43 -0500 Subject: [PATCH 09/10] accept ideographic space as tag separator See also 6877cb0. --- anki/tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/anki/tags.py b/anki/tags.py index aff74082e..e752fdb7c 100644 --- a/anki/tags.py +++ b/anki/tags.py @@ -109,7 +109,7 @@ class TagManager(object): def split(self, tags): "Parse a string and return a list of tags." - return [t for t in tags.split(" ") if t] + return [t for t in tags.replace(u'\u3000', ' ').split(" ") if t] def join(self, tags): "Join tags into a single string, with leading and trailing spaces." From f9f007e5c46a2139e825d3747068fb3fb062ec7a Mon Sep 17 00:00:00 2001 From: "Soren I. Bjornstad" Date: Sun, 17 Aug 2014 13:46:08 -0500 Subject: [PATCH 10/10] add C. van Rooyen to contributors --- aqt/about.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aqt/about.py b/aqt/about.py index 21a6e6004..650695d47 100644 --- a/aqt/about.py +++ b/aqt/about.py @@ -28,7 +28,7 @@ system. It's free and open source.") "" abouttext += '

' + _("Written by Damien Elmes, with patches, translation,\ testing and design from:

%(cont)s") % {'cont': u"""Aaron Harsh, Ádám Szegi, -Alex Fraser, Andreas Klauer, Andrew Wright, Bernhard Ibertsberger, Charlene Barina, +Alex Fraser, Andreas Klauer, Andrew Wright, Bernhard Ibertsberger, C. van Rooyen, Charlene Barina, Christian Krause, Christian Rusche, David Smith, Dave Druelinger, Dotan Cohen, Emilio Wuerges, Emmanuel Jarri, Frank Harper, Gregor Skumavc, H. Mijail, Houssam Salem, Ian Lewis, Immanuel Asmus, Iroiro, Jarvik7,