From f2f758963ae94f87744485028f36a2bb31110588 Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Thu, 11 Jul 2019 15:47:59 +0200 Subject: [PATCH 1/7] Allow field history to be used everywhere --- .../editor_field_history.py | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/editor_field_history/editor_field_history.py b/src/editor_field_history/editor_field_history.py index 243bc66..20f4965 100644 --- a/src/editor_field_history/editor_field_history.py +++ b/src/editor_field_history/editor_field_history.py @@ -147,20 +147,22 @@ def restoreEditorFields(self, mode): if not self.note: # catch invalid state return - # Gather note info fld = self.currentField if fld is None and mode in ("history", "field"): # only necessary on anki20 tooltip("Please select a field whose last entry you want to restore.") return False - did = self.parentWindow.deckChooser.selectedId() - deck = self.mw.col.decks.nameOrNone(did) model = self.note.model() + if hasattr(self.parentWindow, "deckChooser"): + did = self.parentWindow.deckChooser.selectedId() + deck = self.mw.col.decks.nameOrNone(did) + where = "deck" + if deck: + query = "deck:'%s'" % (deck) + else: + query = "" + where = "collection" - # Perform search - if deck: - query = "deck:'%s'" % (deck) - results = self.note.col.findNotes(query) if not results: tooltip("Could not find any past notes in current deck.
" "If you just imported a deck you might have to restart Anki.") @@ -186,6 +188,8 @@ def restoreEditorFields(self, mode): # Assign hotkeys def onSetupButtons20(editor): + t = QShortcut(QKeySequence(history_window_shortcut), editor.parentWindow) + t.activated.connect(lambda: editor.restoreEditorFields("history")) if not isinstance(editor.parentWindow, AddCards): return # only enable in add cards dialog t = QShortcut(QKeySequence(full_restore_shortcut), editor.parentWindow) @@ -194,26 +198,24 @@ def onSetupButtons20(editor): t.activated.connect(lambda: editor.restoreEditorFields("partial")) t = QShortcut(QKeySequence(field_restore_shortcut), editor.parentWindow) t.activated.connect(lambda: editor.restoreEditorFields("field")) - t = QShortcut(QKeySequence(history_window_shortcut), editor.parentWindow) - t.activated.connect(lambda: editor.restoreEditorFields("history")) def onSetupShortcuts21(cuts, editor): - if not isinstance(editor.parentWindow, AddCards): - return # only enable in AddCards dialog added_shortcuts = [ - (full_restore_shortcut, - lambda: editor.restoreEditorFields("full"), True), - (partial_restore_shortcut, - lambda: editor.restoreEditorFields("partial"), True), - (field_restore_shortcut, - lambda: editor.restoreEditorFields("field")), (history_window_shortcut, lambda: editor.restoreEditorFields("history")), ] + if isinstance(editor.parentWindow, AddCards): + added_shortcuts += [ + (full_restore_shortcut, + lambda: editor.restoreEditorFields("full"), True), + (partial_restore_shortcut, + lambda: editor.restoreEditorFields("partial"), True), + (field_restore_shortcut, + lambda: editor.restoreEditorFields("field")), + ] cuts.extend(added_shortcuts) - # Hooks and monkey-patches: Editor.restoreEditorFields = restoreEditorFields From dd617883b4d551a84eaff5e1de04e7a79143ecc1 Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Thu, 11 Jul 2019 16:13:11 +0200 Subject: [PATCH 2/7] Allow to use default values for each fields --- .../editor_field_history.py | 100 ++++++++++++------ 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/src/editor_field_history/editor_field_history.py b/src/editor_field_history/editor_field_history.py index 20f4965..b2fa7fb 100644 --- a/src/editor_field_history/editor_field_history.py +++ b/src/editor_field_history/editor_field_history.py @@ -16,6 +16,7 @@ # Anki's built-in add-on configuration menu history_window_shortcut = "Ctrl+Alt+H" +predefined_window_shortcut = "Ctrl+Alt+P" field_restore_shortcut = "Alt+Z" partial_restore_shortcut = "Alt+Shift+Z" full_restore_shortcut = "Ctrl+Alt+Shift+Z" @@ -42,6 +43,7 @@ if ANKI21: config = mw.addonManager.getConfig(__name__) history_window_shortcut = config["historyWindowShortcut"] + predefined_window_shortcut = config["predefinedWindowShortcut"] field_restore_shortcut = config["fieldRestoreShortcut"] partial_restore_shortcut = config["partialRestoreShortcut"] full_restore_shortcut = config["fullRestoreShortcut"] @@ -76,15 +78,36 @@ def showCompleter(self): self.completer.complete() -def myGetField(parent, question, last_val, **kwargs): - edit = CustomTextEdit(parent, last_val) - ret = getText(question, parent, edit=edit, **kwargs) - return ret +def myGetField(parent, question, potential_vals, **kwargs): + striped_vals = {} + keys = [] + for val in potential_vals: + if not val.strip(): + continue + striped_val = stripHTML(val) + striped_vals[striped_val] = val + keys.append(striped_val) + edit = CustomTextEdit(parent, potential_vals) + (text, ret) = getText(question, parent, edit=edit, **kwargs) + return striped_vals.get(text, False) + + +def predefinedRestore(self, model, fld): + field = model['flds'][fld]['name'] + keys = config.get("predefinedFields", dict()).get(field, []) + if not keys: + tooltip("No predefined values for this field. Edit the configuration.") + return False + txt = "Set field to:" + text = myGetField(self.parentWindow, + txt, keys, title="Predefined fields") + if text: + self.note[field] = text def historyRestore(self, mode, results, model, fld): field = model['flds'][fld]['name'] - last_val = {} + last_vals = {} keys = [] for nid in results[:100]: oldNote = self.note.col.getNote(nid) @@ -99,18 +122,17 @@ def historyRestore(self, mode, results, model, fld): text = stripHTML(html) else: text = None - if text and text not in last_val: + if text and text not in last_vals: keys.append(text) - last_val[text] = html - if not last_val: + last_vals[text] = html + if not last_vals: tooltip("No prior entries for this field found.") return False txt = "Set field to:" - (text, ret) = myGetField(self.parentWindow, + text = myGetField(self.parentWindow, txt, keys, title="Field History") - if not ret or not text.strip() or text not in last_val: - return False - self.note[field] = last_val[text] + if text: + self.note[field] = text def quickRestore(self, mode, results, model, fld): @@ -147,33 +169,42 @@ def restoreEditorFields(self, mode): if not self.note: # catch invalid state return + # Gather note info fld = self.currentField - if fld is None and mode in ("history", "field"): + if fld is None and mode in ("history", "field", "predefined"): # only necessary on anki20 tooltip("Please select a field whose last entry you want to restore.") return False model = self.note.model() - if hasattr(self.parentWindow, "deckChooser"): - did = self.parentWindow.deckChooser.selectedId() - deck = self.mw.col.decks.nameOrNone(did) - where = "deck" - if deck: - query = "deck:'%s'" % (deck) - else: - query = "" - where = "collection" - if not results: - tooltip("Could not find any past notes in current deck.
" - "If you just imported a deck you might have to restart Anki.") - return False - results.sort(reverse=True) - - # Get user selection - if mode == "history": - ret = historyRestore(self, mode, results, model, fld) + # for predefined, don't compute deck info + if mode == "predefined": + ret = predefinedRestore(self, model, fld) + if ret is False: + return False else: - ret = quickRestore(self, mode, results, model, fld) + # Perform search + if hasattr(self.parentWindow, "deckChooser"): + did = self.parentWindow.deckChooser.selectedId() + deck = self.mw.col.decks.nameOrNone(did) + where = "deck" + if deck: + query = "deck:'%s'" % (deck) + else: + query = "" + where = "collection" + results = self.note.col.findNotes(query) + if not results: + tooltip(f"Could not find any past notes in current {where}.
" + "If you just imported a deck you might have to restart Anki.") + return False + results.sort(reverse=True) + + # Get user selection + if mode == "history": + ret = historyRestore(self, mode, results, model, fld) + else: + ret = quickRestore(self, mode, results, model, fld) if ret is False: return False @@ -190,6 +221,8 @@ def restoreEditorFields(self, mode): def onSetupButtons20(editor): t = QShortcut(QKeySequence(history_window_shortcut), editor.parentWindow) t.activated.connect(lambda: editor.restoreEditorFields("history")) + t = QShortcut(QKeySequence(predefined_window_shortcut), editor.parentWindow) + t.activated.connect(lambda: editor.restoreEditorFields("predefined")) if not isinstance(editor.parentWindow, AddCards): return # only enable in add cards dialog t = QShortcut(QKeySequence(full_restore_shortcut), editor.parentWindow) @@ -204,6 +237,8 @@ def onSetupShortcuts21(cuts, editor): added_shortcuts = [ (history_window_shortcut, lambda: editor.restoreEditorFields("history")), + (predefined_window_shortcut, + lambda: editor.restoreEditorFields("predefined")), ] if isinstance(editor.parentWindow, AddCards): added_shortcuts += [ @@ -216,6 +251,7 @@ def onSetupShortcuts21(cuts, editor): ] cuts.extend(added_shortcuts) + # Hooks and monkey-patches: Editor.restoreEditorFields = restoreEditorFields From 6f34d6e355e2ad795b68f84cc6a92b1915d8c9bd Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Thu, 11 Jul 2019 16:17:43 +0200 Subject: [PATCH 3/7] adding config.json (this should be present in the zip file) --- .gitignore | 1 - src/editor_field_history/config.json | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/editor_field_history/config.json diff --git a/.gitignore b/.gitignore index f98ba23..1b54120 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ __pycache__/ # Anki src/*/meta.json -src/*/config.json # Build files build src/*/forms* diff --git a/src/editor_field_history/config.json b/src/editor_field_history/config.json new file mode 100644 index 0000000..86d7cd5 --- /dev/null +++ b/src/editor_field_history/config.json @@ -0,0 +1,13 @@ +{ + "historyWindowShortcut": "Ctrl+Alt+H", + "predefinedWindowShortcut": "Ctrl+Alt+P", + "fieldRestoreShortcut": "Alt+Z", + "partialRestoreShortcut": "Alt+Shift+Z", + "fullRestoreShortcut": "Ctrl+Alt+Shift+Z", + "partialRestoreFields": [], + "predefinedFields":{ + "Example of name of field": [ + "Example of default value", + "other example of default value" + ]} +} From 98a1ed530a0d9e650ec0b649d5998cace9dc78bb Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Thu, 11 Jul 2019 23:05:46 +0200 Subject: [PATCH 4/7] Allow to decide whether a search is done on deck or on Collection --- src/editor_field_history/config.json | 1 + src/editor_field_history/editor_field_history.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/editor_field_history/config.json b/src/editor_field_history/config.json index 86d7cd5..40ef43a 100644 --- a/src/editor_field_history/config.json +++ b/src/editor_field_history/config.json @@ -1,4 +1,5 @@ { + "limit search to deck": true, "historyWindowShortcut": "Ctrl+Alt+H", "predefinedWindowShortcut": "Ctrl+Alt+P", "fieldRestoreShortcut": "Alt+Z", diff --git a/src/editor_field_history/editor_field_history.py b/src/editor_field_history/editor_field_history.py index b2fa7fb..a1600a9 100644 --- a/src/editor_field_history/editor_field_history.py +++ b/src/editor_field_history/editor_field_history.py @@ -184,7 +184,7 @@ def restoreEditorFields(self, mode): return False else: # Perform search - if hasattr(self.parentWindow, "deckChooser"): + if config.get("limit search to deck", True) and hasattr(self.parentWindow, "deckChooser"): did = self.parentWindow.deckChooser.selectedId() deck = self.mw.col.decks.nameOrNone(did) where = "deck" From 3b18384ed8c6ddf6d3c8f9caff89e78e9ec5c952 Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Thu, 11 Jul 2019 23:06:53 +0200 Subject: [PATCH 5/7] Allow to consider more cards in history --- src/editor_field_history/config.json | 1 + src/editor_field_history/editor_field_history.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/editor_field_history/config.json b/src/editor_field_history/config.json index 40ef43a..ef409be 100644 --- a/src/editor_field_history/config.json +++ b/src/editor_field_history/config.json @@ -1,5 +1,6 @@ { "limit search to deck": true, + "number of note to consider in history": 100, "historyWindowShortcut": "Ctrl+Alt+H", "predefinedWindowShortcut": "Ctrl+Alt+P", "fieldRestoreShortcut": "Alt+Z", diff --git a/src/editor_field_history/editor_field_history.py b/src/editor_field_history/editor_field_history.py index a1600a9..40222a3 100644 --- a/src/editor_field_history/editor_field_history.py +++ b/src/editor_field_history/editor_field_history.py @@ -109,7 +109,7 @@ def historyRestore(self, mode, results, model, fld): field = model['flds'][fld]['name'] last_vals = {} keys = [] - for nid in results[:100]: + for nid in results[:config.get("number of note to consider in history", 100)]: oldNote = self.note.col.getNote(nid) if field in oldNote: html = oldNote[field] From 3b23bc6be494b5e0a10782e05aa937fe97e0cb6f Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Thu, 11 Jul 2019 23:16:08 +0200 Subject: [PATCH 6/7] allow to change configuration without restarting anki --- src/editor_field_history/config.py | 30 +++++++++++++++++++ .../editor_field_history.py | 20 ++++++------- 2 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 src/editor_field_history/config.py diff --git a/src/editor_field_history/config.py b/src/editor_field_history/config.py new file mode 100644 index 0000000..11cf996 --- /dev/null +++ b/src/editor_field_history/config.py @@ -0,0 +1,30 @@ +from aqt import mw +import sys + +userOption = None + +def getUserOption(key = None, default = None): + #print(f"getUserOption(key = {key}, default = {default})") + global userOption + if userOption is None: + userOption = mw.addonManager.getConfig(__name__) + #debug("userOption read from the file and is {userOption}") + if key is None: + #debug("return {userOption}") + return userOption + if key in userOption: + #debug("key in userOption. Returning {userOption[key]}") + return userOption[key] + else: + #debug("key not in userOption. Returning default.") + return default + +def writeConfig(): + mw.addonManager.writeConfig(__name__,userOption) + +def update(_): + global userOption, fromName + userOption = None + fromName = None + +mw.addonManager.setConfigUpdatedAction(__name__,update) diff --git a/src/editor_field_history/editor_field_history.py b/src/editor_field_history/editor_field_history.py index 40222a3..6ad1342 100644 --- a/src/editor_field_history/editor_field_history.py +++ b/src/editor_field_history/editor_field_history.py @@ -38,16 +38,16 @@ from anki import version ANKI21 = version.startswith("2.1") +from .config import getConfig if ANKI21: - config = mw.addonManager.getConfig(__name__) - history_window_shortcut = config["historyWindowShortcut"] - predefined_window_shortcut = config["predefinedWindowShortcut"] - field_restore_shortcut = config["fieldRestoreShortcut"] - partial_restore_shortcut = config["partialRestoreShortcut"] - full_restore_shortcut = config["fullRestoreShortcut"] - partial_restore_fields = config["partialRestoreFields"] + history_window_shortcut = getConfig("historyWindowShortcut", "Ctrl+Alt+H") + predefined_window_shortcut = getConfig("predefinedWindowShortcut", "Ctrl+Alt+P") + field_restore_shortcut = getConfig("fieldRestoreShortcut", "Alt+Z") + partial_restore_shortcut = getConfig("partialRestoreShortcut", "Alt+Shift+Z") + full_restore_shortcut = getConfig("fullRestoreShortcut", "Ctrl+Alt+Shift+Z") + partial_restore_fields = getConfig("partialRestoreFields", []) # Ctrl+Alt+H is a global hotkey on macOS # Hacky solution for anki21. A platform-specific config.json would be @@ -94,7 +94,7 @@ def myGetField(parent, question, potential_vals, **kwargs): def predefinedRestore(self, model, fld): field = model['flds'][fld]['name'] - keys = config.get("predefinedFields", dict()).get(field, []) + keys = getConfig("predefinedFields", dict()).get(field, []) if not keys: tooltip("No predefined values for this field. Edit the configuration.") return False @@ -109,7 +109,7 @@ def historyRestore(self, mode, results, model, fld): field = model['flds'][fld]['name'] last_vals = {} keys = [] - for nid in results[:config.get("number of note to consider in history", 100)]: + for nid in results[:getConfig("number of note to consider in history", 100)]: oldNote = self.note.col.getNote(nid) if field in oldNote: html = oldNote[field] @@ -184,7 +184,7 @@ def restoreEditorFields(self, mode): return False else: # Perform search - if config.get("limit search to deck", True) and hasattr(self.parentWindow, "deckChooser"): + if getConfig("limit search to deck", True) and hasattr(self.parentWindow, "deckChooser"): did = self.parentWindow.deckChooser.selectedId() deck = self.mw.col.decks.nameOrNone(did) where = "deck" From 016feac1b638f43c1583f8581f7d03dec7de389a Mon Sep 17 00:00:00 2001 From: Arthur Milchior Date: Tue, 30 Jul 2019 06:21:21 +0200 Subject: [PATCH 7/7] Adding configuration for shortcut --- src/browser_refresh/browser_refresh.py | 13 ++++--------- src/browser_refresh/config.json | 1 + src/browser_refresh/config.py | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 src/browser_refresh/config.json create mode 100644 src/browser_refresh/config.py diff --git a/src/browser_refresh/browser_refresh.py b/src/browser_refresh/browser_refresh.py index 715beb6..48ae51d 100644 --- a/src/browser_refresh/browser_refresh.py +++ b/src/browser_refresh/browser_refresh.py @@ -7,14 +7,12 @@ (e.g. to show newly added cards since last search) Copyright: (c) Glutanimate 2016-2017 -2018 Arthur Milchior (porting to 2.1) License: GNU AGPLv3 or later """ # Do not modify the following line from __future__ import unicode_literals -from anki import version as anki_version -anki21 = anki_version.startswith("2.1.") +from .config import getConfig ######## USER CONFIGURATION START ######## @@ -41,15 +39,12 @@ from aqt.browser import Browser from anki.hooks import addHook def debug(t): - #print(t) + print(t) pass def refreshView(self): debug("Calling refreshView()") - if anki21: - self.onSearchActivated() - else: - self.onSearch(reset=True) + self.onSearchActivated() if SORTING_COLUMN: try: col_index = self.model.activeCols.index(SORTING_COLUMN) @@ -62,7 +57,7 @@ def setupMenu(self): menu = self.form.menuEdit menu.addSeparator() a = menu.addAction('Refresh View') - a.setShortcut(QKeySequence("CTRL+F5" if anki21 else "F5")) + a.setShortcut(QKeySequence(getConfig("ShortCut","CTRL+F5"))) a.triggered.connect(self.refreshView) Browser.refreshView = refreshView diff --git a/src/browser_refresh/config.json b/src/browser_refresh/config.json new file mode 100644 index 0000000..718d53a --- /dev/null +++ b/src/browser_refresh/config.json @@ -0,0 +1 @@ +{"ShortCut": "CTRL+F5"} diff --git a/src/browser_refresh/config.py b/src/browser_refresh/config.py new file mode 100644 index 0000000..09908c1 --- /dev/null +++ b/src/browser_refresh/config.py @@ -0,0 +1,25 @@ +from aqt import mw + +options = None +def readIfRequired(): + global options + if options is None: + options = mw.addonManager.getConfig(__name__) or dict() + +def newConf(config): + global options + options = None + +def getConfig(s = None, default = None): + """Get the dictionnary of objects. If a name is given, return the + object with this name if it exists. + + reads if required.""" + + readIfRequired() + if s is None: + return options + else: + return options.get(s, default) + +mw.addonManager.setConfigUpdatedAction(__name__,newConf)