def test_genrem(): d = getEmptyDeck() f = d.newNote() f['Front'] = u'1' f['Back'] = u'' d.addNote(f) assert len(f.cards()) == 1 m = d.models.current() mm = d.models # adding a new template should automatically create cards t = mm.newTemplate("rev") t['qfmt'] = '{{Front}}' t['afmt'] = "" mm.addTemplate(m, t) mm.save(m, templates=True) assert len(f.cards()) == 2 # if the template is changed to remove cards, they'll be removed t['qfmt'] = "{{Back}}" mm.save(m, templates=True) assert len(f.cards()) == 1 # if we add to the note, a card should be automatically generated f.load() f['Back'] = "1" f.flush() assert len(f.cards()) == 2 # deleteion calls a hook to let the user abort the delete. let's abort it: def abort(val, *args): return False addHook("remEmptyCards", abort) f['Back'] = "" f.flush() assert len(f.cards()) == 2
def init(): mw.mainWin.actionJapaneseAudioDownload = QAction(mw) mw.mainWin.actionJapaneseAudioDownloadQuery = QAction(mw) icon = QIcon() # icon.addPixmap(QPixmap(getLogoFile(u"audio_download.png")),QIcon.Normal,QIcon.Off) icon.addPixmap(QPixmap(getLogoFile(u"speaker_down_32.png")),QIcon.Normal,QIcon.Off) mw.mainWin.actionJapaneseAudioDownload.setIcon(icon) mw.mainWin.actionJapaneseAudioDownload.setIconText(u"Audio Download") # Hmm. I don’t really know what the ‘_’ is about. Copy-and-pasted. mw.mainWin.actionJapaneseAudioDownload.setShortcut(_("Ctrl+J")) mw.mainWin.actionJapaneseAudioDownload.setEnabled(False) mw.connect(mw.mainWin.actionJapaneseAudioDownload,SIGNAL("triggered()"),downloadAudio) # I really want to jiggle the action for each new card/question. # mw.connect(mw,SIGNAL("nextCard()"),toggleDownloadAction) mw.mainWin.actionJapaneseAudioDownloadQuery.setIcon(icon) mw.mainWin.actionJapaneseAudioDownloadQuery.setIconText(u"Audio Download...") mw.mainWin.actionJapaneseAudioDownloadQuery.setShortcut(_("Ctrl+Shift+J")) mw.connect(mw.mainWin.actionJapaneseAudioDownloadQuery,SIGNAL("triggered()"),downloadAudioQuery) mw.mainWin.menuEdit.addSeparator() if not AUTO_DOWNLOAD_AUDIO: mw.mainWin.toolBar.addSeparator() mw.mainWin.toolBar.addAction(mw.mainWin.actionJapaneseAudioDownload) mw.mainWin.menuEdit.addAction(mw.mainWin.actionJapaneseAudioDownload) mw.mainWin.menuEdit.addAction(mw.mainWin.actionJapaneseAudioDownloadQuery) addHook('disableCardMenuItems', disableDownloadAction) addHook('enableCardMenuItems', enableDownloadAction)
def run(self): # setup progress handler self.byteUpdate = time.time() self.recvTotal = 0 def recvEvent(bytes): self.recvTotal += bytes self.recv.emit() addHook("httpRecv", recvEvent) client = AnkiRequestsClient() try: resp = client.get( aqt.appShared + "download/%d" % self.code) if resp.status_code == 200: data = client.streamContent(resp) elif resp.status_code in (403,404): self.error = _("Invalid code") return else: self.error = _("Error downloading: %s" % resp.status_code) return except Exception as e: exc = traceback.format_exc() try: self.error = str(e[0]) except: self.error = str(exc) return finally: remHook("httpRecv", recvEvent) self.fname = re.match("attachment; filename=(.+)", resp.headers['content-disposition']).group(1) self.data = data
def __init__(self, mw): if isMac: # use a separate window on os x so we can a clean menu QDialog.__init__(self, None, Qt.Window) else: QDialog.__init__(self, mw) QDialog.__init__(self, None, Qt.Window) self.mw = mw self.form = aqt.forms.editcurrent.Ui_Dialog() self.form.setupUi(self) self.setWindowTitle(_("Edit Current")) self.setMinimumHeight(400) self.setMinimumWidth(500) self.connect(self, SIGNAL("rejected()"), self.onSave) self.form.buttonBox.button(QDialogButtonBox.Close).setShortcut( QKeySequence("Ctrl+Return")) self.editor = aqt.editor.Editor(self.mw, self.form.fieldsArea, self) self.editor.setNote(self.mw.reviewer.card.note()) restoreGeom(self, "editcurrent") addHook("reset", self.onReset) self.mw.requireReset() self.show() # reset focus after open self.editor.web.setFocus()
def run(self): # setup progress handler self.byteUpdate = time.time() self.recvTotal = 0 def canPost(): if (time.time() - self.byteUpdate) > 0.1: self.byteUpdate = time.time() return True def recvEvent(bytes): self.recvTotal += bytes if canPost(): self.recv.emit() addHook("httpRecv", recvEvent) con = httpCon() try: resp, cont = con.request(aqt.appShared + "download/%d" % self.code) except Exception, e: exc = traceback.format_exc() try: self.error = unicode(e[0], "utf8", "ignore") except: self.error = unicode(exc, "utf8", "ignore") return
def __init__(self, parent): if parent.config['standaloneWindows']: windParent = None else: windParent = parent QDialog.__init__(self, windParent, Qt.Window) self.parent = parent ui.utils.applyStyles(self) self.config = parent.config self.dialog = ankiqt.forms.addcards.Ui_AddCards() self.dialog.setupUi(self) self.setWindowTitle(_("Add Items - %s") % parent.deck.name()) self.setupEditor() self.addChooser() self.addButtons() self.setupStatus() self.modelChanged() self.addedItems = 0 self.forceClose = False restoreGeom(self, "add") restoreSplitter(self.dialog.splitter, "add") self.dialog.splitter.setChildrenCollapsible(True) self.show() addHook('guiReset', self.modelChanged) ui.dialogs.open("AddCards", self)
def run(self): # setup progress handler self.byteUpdate = time.time() self.recvTotal = 0 def canPost(): if (time.time() - self.byteUpdate) > 0.1: self.byteUpdate = time.time() return True def recvEvent(bytes): self.recvTotal += bytes if canPost(): self.recv.emit() addHook("httpRecv", recvEvent) con = httpCon() try: resp, cont = con.request( aqt.appShared + "download/%d" % self.code) except Exception as e: exc = traceback.format_exc() try: self.error = str(e[0]) except: self.error = str(exc) return finally: remHook("httpRecv", recvEvent) if resp['status'] == '200': self.error = None self.fname = re.match("attachment; filename=(.+)", resp['content-disposition']).group(1) self.data = cont elif resp['status'] == '403': self.error = _("Invalid code.") else: self.error = _("Error downloading: %s") % resp['status']
def addBrowserSelectionCmd( menuLabel, preF, perF, postF, tooltip=None, shortcut=None, progLabel='Working...' ): def setupMenu( b ): a = QAction( menuLabel, b ) if tooltip: a.setStatusTip( tooltip ) if shortcut: a.setShortcut( QKeySequence( *shortcut ) ) b.connect( a, SIGNAL('triggered()'), lambda b=b: doOnSelection( b, preF, perF, postF, progLabel ) ) b.form.menuEdit.addAction( a ) addHook( 'browser.setupMenus', setupMenu )
def addDoOnSelectionBtn( btnTxt, overviewMsg, progMsg, preF, perF, postF, shortcut=None ): def setupMenu( ed ): a = QAction( btnTxt, ed ) if shortcut: a.setShortcut( shortcut ) ed.connect( a, SIGNAL('triggered()'), lambda e=ed: doOnSelection( e, overviewMsg, progMsg, preF, perF, postF ) ) if not parentMenu: setupParentMenu( ed ) parentMenu.addAction( a ) addHook( 'editor.setupMenus', setupMenu )
def addBrowserItem( menuLabel, func_triggered, tooltip=None, shortcut=None): def setupMenu( b ): a = QAction( menuLabel, b ) if tooltip: a.setStatusTip( tooltip ) if shortcut: a.setShortcut( QKeySequence( *shortcut ) ) b.connect( a, SIGNAL('triggered()'), lambda b=b: func_triggered(b) ) b.form.menuEdit.addAction( a ) addHook( 'browser.setupMenus', setupMenu )
def setupHooks(self): addHook("modSchema", self.onSchemaMod) addHook("remNotes", self.onRemNotes) addHook("odueInvalid", self.onOdueInvalid) addHook("mpvWillPlay", self.onMpvWillPlay) addHook("mpvIdleHook", self.onMpvIdle) self._activeWindowOnPlay = None
def install(self): from anki.hooks import addHook, remHook # Install hook into focus event of Anki: we regenerate the model information when # the cursor moves from the Expression/Reading/whatever field to another field log.info("Installing focus hook") # Unconditionally add our new hook to Anki addHook('editFocusLost', self.onFocusLost)
def profileLoaded(): """Support for Advanced Previewer""" try: from advanced_previewer.previewer import Previewer except ImportError: return Previewer.linkHandler = wrap( Previewer.linkHandler, linkHandler, "around") addHook("previewerMungeQA", linkInserter)
def __init__(self, mw): self.mw = mw self.web = mw.web self.card = None self.cardQueue = [] self.hadCardQueue = False self._answeredIds = [] self.state = None self.bottom = aqt.toolbar.BottomBar(mw, mw.bottomWeb) addHook("leech", self.onLeech)
def __init__(self, mw, widget, label=True, start=None): QHBoxLayout.__init__(self) self.widget = widget self.mw = mw self.label = label self.setMargin(0) self.setSpacing(8) self.setupDecks() self.widget.setLayout(self) addHook('currentModelChanged', self.onModelChange)
def __init__(self, mw): self.mw = mw self.web = mw.web self.card = None self.cardQueue = [] self._answeredIds = [] self.state = None self.keep = False self._setupStatus() addHook("leech", self.onLeech)
def __init__(self, mw, widget, label=True): QHBoxLayout.__init__(self) self.widget = widget self.mw = mw self.deck = mw.col self.label = label self.setMargin(0) self.setSpacing(8) self.setupModels() addHook('reset', self.onReset) self.widget.setLayout(self)
def __init__(self, mw, widget, label=True): QHBoxLayout.__init__(self) self.widget = widget self.mw = mw self.currentModel = sendToAnki("modelByName", {"name": "Basic"}) self.label = label self.setMargin(0) self.setSpacing(8) self.setupModels() addHook('reset', self.onReset) self.widget.setLayout(self)
def init_kanji_info(): kanji_info_txt = os.path.join(mw.pm.addonFolder(), "kanji_info.txt") read_kanji_info(kanji_info_txt) if not len(kanji_info): # gracefully also check Anki main dir print "kanji_info", kanji_info_version, "please put kanji_info.txt in", kanji_info_txt print "kanji_info", kanji_info_version, "found", len(kanji_info), "entries" if len(kanji_info): addHook("showAnswer", append_kanji_info)
def __init__(self, mw): self.mw = mw self.web = mw.web self.card = None self.cardQueue = [] self.hadCardQueue = False self._answeredIds = [] self._recordedAudio = None self.typeCorrect = None # web init happens before this is set self.state = None self.bottom = aqt.toolbar.BottomBar(mw, mw.bottomWeb) addHook("leech", self.onLeech)
def setup_tips(): read_character_data() read_scripts() # addHook("filterQuestionText", show_tip_filter) ## Uncomment the line above to also show tips on the question. addHook("filterAnswerText", show_tip_filter) ## Looks like we cant just load scripts. So eval them after we've ## done the rest of the card. # addHook("showQuestion", do_scripts) ## Uncomment the line above to also show tips on the question. addHook("showAnswer", do_scripts)
def ht_init(): global ht_menu addHook("profileLoaded",ht_load) addHook("unloadProfile",ht_save) ht_menu = QAction("Hide Button Times", mw, checkable=True) ht_menu.triggered.connect(ht_switch) try: mw.addon_view_menu except AttributeError: mw.addon_view_menu = QMenu(_(u"&View"), mw) mw.form.menubar.insertMenu(mw.form.menuTools.menuAction(), mw.addon_view_menu) mw.addon_view_menu.addAction(ht_menu)
def __init__(self, browser, nids): QDialog.__init__(self, browser) self.browser = browser self.nids = nids self.oldModel = browser.card.note().model() self.form = aqt.forms.changemodel.Ui_Dialog() self.form.setupUi(self) self.setWindowModality(Qt.WindowModal) self.setup() restoreGeom(self, "changeModel") addHook("reset", self.onReset) addHook("currentModelChanged", self.onReset) self.exec_()
def __init__(self, mw): # Right, this is more than a bit weird. The basic issue is that if we were # to just initialize() RIGHT NOW then we will hold the Python import lock, # because Anki __import__s its plugins. This ABSOLUTELY KILLS us when we # come to e.g. build the database on a background thread, because that code # naturally wants to import some stuff, but it doesn't hold the lock! # # To work around this issue, we carefully schedule initialization (and database # construction) for a time when Anki will not have caused us to hold the import lock. # # Debugging this was a fair bit of work! from anki.hooks import addHook addHook("init", lambda: self.initialize(mw))
def nm_onload(): """ Add hooks and initialize menu. Call to this function is placed on the end of this file. """ nm_refresh_css_custom_colors_string() addHook("unloadProfile", nm_save) addHook("profileLoaded", nm_load) addHook("showQuestion", take_care_of_night_class) addHook("showAnswer", take_care_of_night_class) nm_setup_menu() Browser.__init__ = wrap(Browser.__init__, nm_browser_init_after) Editor._addButton = wrap(Editor._addButton, nm_add_button_name, "around") Editor.checkValid = wrap(Editor.checkValid, nm_style_fields) Editor.__init__ = wrap(Editor.__init__, nm_editor_init_after) # Anki 2.1 Deck Browser background colour if appVersion.startswith('2.1'): Editor._loadFinished = wrap(Editor._loadFinished, nm_editor_loadFinished) EditorWebView.setHtml = wrap(EditorWebView.setHtml, nm_editor_web_view_set_html_after) Browser._renderPreview = wrap(Browser._renderPreview, nm_edit_render_preview_after) Browser._cardInfoData = wrap(Browser._cardInfoData, nm_browser_card_info_after, "around") EditCurrent.__init__ = wrap(EditCurrent.__init__, nm_edit_current_init_after) AddCards.__init__ = wrap(AddCards.__init__, nm_add_init_after) CardLayout.renderPreview = wrap(CardLayout.renderPreview, nm_render_preview_after)
def __init__(self, mw, widget, cards=True, label=True): QHBoxLayout.__init__(self) self.widget = widget self.mw = mw self.deck = mw.deck self.handleCards = cards self.label = label self._ignoreReset = False self.setMargin(0) self.setSpacing(4) self.setupModels() self.setupTemplates() addHook('reset', self.onReset) self.widget.setLayout(self)
def __init__(self, mw, names=None, accept=None, title=None, help="studydeck", current=None, cancel=True, parent=None, dyn=False, buttons=[], geomKey="default"): QDialog.__init__(self, parent or mw) self.mw = mw self.form = aqt.forms.studydeck.Ui_Dialog() self.form.setupUi(self) self.form.filter.installEventFilter(self) self.cancel = cancel addHook('reset', self.onReset) self.geomKey = "studyDeck-"+geomKey restoreGeom(self, self.geomKey) if not cancel: self.form.buttonBox.removeButton( self.form.buttonBox.button(QDialogButtonBox.Cancel)) if buttons: for b in buttons: self.form.buttonBox.addButton(b, QDialogButtonBox.ActionRole) else: b = QPushButton(_("Add")) b.setShortcut(QKeySequence("Ctrl+N")) b.setToolTip(shortcut(_("Add New Deck (Ctrl+N)"))) self.form.buttonBox.addButton(b, QDialogButtonBox.ActionRole) b.connect(b, SIGNAL("clicked()"), self.onAddDeck) if title: self.setWindowTitle(title) if not names: names = sorted(self.mw.col.decks.allNames(dyn=dyn)) self.nameFunc = None self.origNames = names else: self.nameFunc = names self.origNames = names() self.name = None self.ok = self.form.buttonBox.addButton( accept or _("Study"), QDialogButtonBox.AcceptRole) self.setWindowModality(Qt.WindowModal) self.connect(self.form.buttonBox, SIGNAL("helpRequested()"), lambda: openHelp(help)) self.connect(self.form.filter, SIGNAL("textEdited(QString)"), self.redraw) self.connect(self.form.list, SIGNAL("itemDoubleClicked(QListWidgetItem*)"), self.accept) self.show() # redraw after show so position at center correct self.redraw("", current) self.exec_()
def anknotes_onload(): # write_file_contents('%s: anknotes_onload' % __name__, 'load') if in_anki(): addHook("profileLoaded", anknotes_profile_loaded) if ANKNOTES.HOOKS.DB: DB.scalar = anknotes_scalar # wrap(DB.scalar, anknotes_scalar, "before") DB.execute = wrap(DB.execute, anknotes_execute, "before") if ANKNOTES.HOOKS.SEARCH: addHook("search", anknotes_search_hook) Finder._query = wrap(Finder._query, anknotes_finder_query_wrap, "around") Finder.findCards = wrap(Finder.findCards, anknotes_finder_findCards_wrap, "around") browser.Browser._systemTagTree = wrap(browser.Browser._systemTagTree, anknotes_browser_tagtree_wrap, "around") # write_file_contents('%s: anknotes_onload: anknotes_setup_menu' % __name__, 'load') menu.anknotes_setup_menu() Preferences.setupOptions = wrap(Preferences.setupOptions, settings.setup_evernote)
def __init__(self): self.languages = dict() self.preferences = Preferences() self.preferences.load() if not self.loadLanguages(): def downloadDictionaries(): showInfo(_("No Yomichan dictionaries found\nDownloading now")) ret = download(aqt.mw, 2027900559) if not ret: raise Exception("Could not download dictionary files") data, fname = ret aqt.mw.addonManager.install(data, fname) aqt.mw.progress.finish() addHook('profileLoaded',downloadDictionaries) self.loadSubscriptions()
def __init__(self, mw): self.mw = mw self.web = mw.web self.card = None self.cardQueue = [] self.hadCardQueue = False self._answeredIds = [] self._recordedAudio = None self.typeCorrect = None # web init happens before this is set self.state = None self.bottom = aqt.toolbar.BottomBar(mw, mw.bottomWeb) # qshortcut so we don't autorepeat self.delShortcut = QShortcut(QKeySequence("Delete"), self.mw) self.delShortcut.setAutoRepeat(False) self.mw.connect(self.delShortcut, SIGNAL("activated()"), self.onDelete) addHook("leech", self.onLeech)
import ssl import sys from anki.hooks import addHook from anki.utils import isMac sys.dont_write_bytecode = True if isMac: ssl._create_default_https_context = ssl._create_unverified_context ############## other config here ################## shortcut = ('Ctrl+Alt' if isMac else 'Ctrl') + '+Q' ################################################### def start_here(): from . import common as fastwq from .context import config config.read() fastwq.my_shortcut = shortcut if not fastwq.have_setup: fastwq.have_setup = True fastwq.config_menu() fastwq.browser_menu() fastwq.context_menu() fastwq.customize_addcards() addHook("profileLoaded", start_here)
def deckStatsInit21(self, mw): self.form.web.onBridgeCmd = self._linkHandler # refresh heatmap on options change: addHook('reset', self.refresh)
newf = self.stripNewLines(newf) newf = TAB + TAB + newf.replace("\n", "\n" + TAB + TAB) latexnote.append(TAB + r"\begin{plain}" + "\n" + newf + "\n" + TAB + r"\end{plain}") #remove empty fields at the end of the note: while latexnote[-1] == TAB + r"\xplain{}": latexnote.pop() # tags if self.includeTags: cleantag = tags.strip() if cleantag != "": latexnote.append(TAB + r"\tags{" + tags.strip() + r"}") latexnote.append(r"\end{note}" + "\n") data.append("\n".join(latexnote)) self.count = len(data) #preamble =r"""# -- I've decided that this should be placed in model["latexPre"] by the user #\newenvironment{note}{}{\begin{center}\rule{\textwidth}{2pt}\end{center}} #\newenvironment{field}{}{\begin{center}\rule{\textwidth}{0.4pt}\end{center}} #\newcommand*{\tags}[1]{\paragraph{tags: }#1}""" out = "% -*- coding: utf-8 -*-\n" + model[ "latexPre"] + "\n" + "\n".join(data) + "\n" + model["latexPost"] file.write(out.encode("utf-8")) def addLatexExporterToList(exps): exps.append((LatexNoteExporter.key + " (*" + LatexNoteExporter.ext + r")", LatexNoteExporter)) addHook("exportersList", addLatexExporterToList)
def run(): def setupMenu(self): # menu = self.form.menuEdit menu = QtWidgets.QMenu('AutoFields', self.form.menubar) if language == 'french': a = menu.addAction('Conjugate French Verbs') a.triggered.connect(lambda _, b=self: setVerbConjugationsForOneNoteFromBrowser(b)) a.setIcon(conj_icon) menu.addSeparator() b = menu.addAction('Get all extra fields') b.triggered.connect(lambda _, b=self: populateExtraFields(b)) b.setIcon(all_icon) menu.addSeparator() c = menu.addAction('Get Etymology') c.triggered.connect(lambda _, c=self: populateEtymology(c)) c.setIcon(etymology_icon) d = menu.addAction('Get IPA') d.triggered.connect(lambda _, d=self: populateIPA(d)) d.setIcon(ipa_icon) e = menu.addAction('Get Audio') e.triggered.connect(lambda _, e=self: populateAudio(e)) e.setIcon(audio_icon) f = menu.addAction('Get POS') f.triggered.connect(lambda _, f=self: populatePos(f)) f.setIcon(pos_icon) g = menu.addAction('Get Plural') g.triggered.connect(lambda _, g=self: populatePlural(g)) g.setIcon(plural_icon) h = menu.addAction('Get Feminine') h.triggered.connect(lambda _, h=self: populateFeminine(h)) h.setIcon(feminine_icon) menu.addSeparator() showAbout = QAction("About", mw) showAbout.triggered.connect(show_info) showAbout.setIcon(about_icon) menu.addAction(showAbout) self.form.menubar.addMenu(menu) else: c = menu.addAction('Etymology') c.triggered.connect(lambda _, c=self: populateEtymology(c)) c.setIcon(etymology_icon) d = menu.addAction('IPA') d.triggered.connect(lambda _, d=self: populateIPA(d)) d.setIcon(ipa_icon) e = menu.addAction('Audio') e.triggered.connect(lambda _, e=self: populateAudio(e)) e.setIcon(audio_icon) f = menu.addAction('POS') f.triggered.connect(lambda _, f=self: populatePos(f)) f.setIcon(pos_icon) g = menu.addAction('Plural') g.triggered.connect(lambda _, g=self: populatePlural(g)) g.setIcon(plural_icon) self.form.menubar.addMenu(menu) showAbout = QAction("About", mw) showAbout.triggered.connect(show_info) showAbout.setIcon(about_icon) menu.addAction(showAbout) addHook("browser.setupMenus", setupMenu)
global addon_path global addonfoldername global addonname global css_templates_folder global mediafolder global css_file_in_media addon_path = os.path.dirname(__file__) addonfoldername = os.path.basename(addon_path) addonname = mw.addonManager.addonName(addonfoldername) css_templates_folder = os.path.join(addon_path, "css") mediafolder = os.path.join(mw.pm.profileFolder(), "collection.media") css_file_in_media = os.path.join(mediafolder, "_styles_for_syntax_highlighting.css") addHook("profileLoaded", set_some_paths) insertscript = """<script> function MyInsertHtml(content) { var s = window.getSelection(); var r = s.getRangeAt(0); r.collapse(true); var mydiv = document.createElement("div"); mydiv.innerHTML = content; r.insertNode(mydiv); // Move the caret r.setStartAfter(mydiv); r.collapse(true); s.removeAllRanges(); s.addRange(r); }
from anki.hooks import addHook from aqt import mw from .config import * def easeAdjustFunc(): mw.reviewer.card.factor = ease_factor addHook('showQuestion', easeAdjustFunc) addHook('showAnswer', easeAdjustFunc)
if path.split('.')[-1] != "db": infoMsg('The selected file was not a db file') return # per() and post() will still execute, but nothing happens db = MorphDb( path ) return { 'b':b, 'db':db, 'tags':str(tags), 'noteCount':noteCount } def per( st, n ): # :: State -> Note -> State notecfg = getFilter(n) if notecfg is None: return st morphemizer = getMorphemizerByName(notecfg['Morphemizer']) for field in notecfg['Fields']: for m in getMorphemes(morphemizer, n[ field ], n.tags): if m in st['db'].db: n.addTag(st['tags']) break n.flush() return st def post( st ): # :: State -> State tooltip(_( 'Tagged {} notes containing morphemes in the selected db with "{}" '.format(st['noteCount'], st['tags']) ) ) return st def runBatchPlay(): label = 'MorphMan: Mass Tagger' tooltipMsg = 'Tag all cards that contain morphemes from db' shortcut = cfg1('set mass tagger key') addBrowserNoteSelectionCmd( label, pre, per, post, tooltip=tooltipMsg, shortcut=(shortcut,) ) addHook( 'profileLoaded', runBatchPlay )
# if we're editing an existing card, flush the changes if note.id != 0: note.flush() return True return flag # Add a colorized kanji to a Diagram whenever leaving a Kanji field def onFocusLost(flag, note, currentFieldIndex): return addKanji(note, flag, currentFieldIndex) addHook('editFocusLost', onFocusLost) # menu item to regenerate all def regenerate_all(): # Find the models that have the right name and fields; faster than # checking every note if not askUser("Do you want to regenerate all kanji diagrams? " 'This may take some time and will overwrite the ' 'destination Diagram fields.'): return models = [m for m in mw.col.models.all() if modelIsCorrectType(m)] # Find the notes in those models and give them kanji for model in models: for nid in mw.col.models.nids(model):
def __addHooks(self): addHook('fmod_jparser', self.injectParser) addHook('fmod_jparser2', self.injectParser2) addHook('fmod_jparser3', self.injectParser3) addHook("showAnswer", self.showAnswer)
global flag flag = True def _showQuestion(): global jsObjectJParser, flag if flag: flag = False mw.web.page().mainFrame().addToJavaScriptWindowObject("pluginObjectJParser", jsObjectJParser) if anki.version < "2.1": mw.reviewer._initWeb=wrap(mw.reviewer._initWeb,_initWeb,"before") mw.reviewer._showQuestion=wrap(mw.reviewer._showQuestion,_showQuestion,"before") #addHook("profileLoaded", addToMenuBar) addHook("profileLoaded", kanji.load) addHook("unloadProfile", kanji.unload) action_label = "Reload Parser" action = None for a in mw.form.menuTools.actions(): if a.text() == action_label: action = a if action: action.triggered.disconnect() else: action = QAction(action_label, mw) mw.form.menuTools.addAction(action) action.triggered.connect(kanji.load)
mw.form.actionFullDatabaseCheck.setIcon( QIcon(os.path.join(icons_dir, 'check-db.png'))) mw.form.actionPreferences.setIcon( QIcon(os.path.join(icons_dir, 'preferences.png'))) ## Hide the edit and nmore buttons. mw.reviewer._bottomCSS += "td.stat button {display:none;}" # Create the menus add_tool_bar() add_more_tool_bar() add_to_menus() #mw.toolbar.web.hide() mw.deckBrowser.show = wrap(mw.deckBrowser.show, edit_actions_off) mw.overview.show = wrap(mw.overview.show, edit_actions_on) mw.reviewer.show = wrap(mw.reviewer.show, edit_actions_on) mw.reviewer.show = wrap(mw.reviewer.show, maybe_more_tool_bar_on) mw.overview.show = wrap(mw.overview.show, more_tool_bar_off) mw.reviewer._toggleStar = wrap(mw.reviewer._toggleStar, update_mark_action) mw.deckBrowser.show = wrap(mw.deckBrowser.show, more_tool_bar_off) # Wrapper to not show a next card. original_next_card = Reviewer.nextCard Reviewer.nextCard = next_card_wrapper # Make sure we don't leave a stale last card button switched on addHook("reviewCleanup", next_card_toggle_off) addHook("unloadProfile", save_toolbars_visible) addHook("profileLoaded", load_toolbars_visible)
def onEditWindow(self): """Launch BrowserEditCurrent instance""" nids = self.selectedNotes() if len(nids) != 1: return self.form.splitter.widget(1).setVisible(False) self.editor.setNote(None) self.externalNid = nids[0] self.editCurrent = aqt.dialogs.open("BrowserEditCurrent", self.mw, self) def onSetupMenus(self): """Create menu entry and set attributes up""" menu = self.form.menuEdit menu.addSeparator() a = menu.addAction('Edit in New Window') a.setShortcut(QKeySequence("Ctrl+Alt+E")) a.triggered.connect(lambda _, o=self: onEditWindow(o)) self.externalNid = None self.editCurrent = None # Register new dialog in DialogManager: dialogs._dialogs["BrowserEditCurrent"] = [BrowserEditCurrent, None] # Hook into menu setup addHook("browser.setupMenus", onSetupMenus) # Modify existing methods Browser.onRowChanged = wrap(Browser.onRowChanged, onRowChanged, "after") Browser.deleteNotes = wrap(Browser.deleteNotes, onDeleteNotes, "before")
tooltip(f'Added tag(s) "%s"{tooltipSuffix}' % map['tags']) return r def new_shortcutKeys(): tag_shortcut = getConfig().get("add tag shortcut", "q") tag_edit_shortcut = getConfig().get("edit tag shortcut", "w") quick_tags = getConfig().get("quick tags", dict()) # end quick_tags sk = [(tag_shortcut, promptAndAddTags), (tag_edit_shortcut, promptAndEditTags)] for key, map in quick_tags.items(): sk.append((key, quick_tag_method(map))) return sk def addShortcuts(shortcuts): usedShortcuts = {presentShortcut: fn for presentShortcut, fn in shortcuts} newShortcuts = new_shortcutKeys() for shortcut, fn in newShortcuts: if shortcut not in usedShortcuts: shortcuts.append((shortcut, fn)) usedShortcuts[shortcut] = fn else: tooltip( f"Warning: shortcut {shortcut} is already used by {usedShortcuts[shortcut]}. Please change it by editing quick tagging's configuration file." ) addHook("reviewStateShortcuts", addShortcuts)
changed += 1 mw.progress.update(label="Processed %d/%d notes" % (c + 1, len(nids))) return changed # true on change def _fixNoteHTML(note): changed = False for fld, val in note.items(): parsed = str(BeautifulSoup(val, "html.parser")) if parsed != val: note[fld] = parsed changed = True if changed: note.flush() return changed def onMenuSetup(browser): act = QAction(browser) act.setText("Fix Invalid HTML") mn = browser.form.menu_Notes mn.addSeparator() mn.addAction(act) act.triggered.connect(lambda b=browser: onFixHTML(browser)) addHook("browser.setupMenus", onMenuSetup)
log.close() def _errMsg(type, texpath): """An error message, in html, concerning LaTeX compilation. This message contains LaTeX outputs if it exists, or a message asking whether the program latex and dvipng/dvisvgm are installed. Keyword arguments type -- the (begin of the) executed command texpath -- the path to the (temporary) file which was compiled """ msg = (_("Error executing %s.") % type) + "<br>" msg += (_("Generated file: %s") % texpath) + "<br>" try: with open(namedtmp("latex_log.txt", rm=False)) as f: log = f.read() if not log: raise Exception() msg += "<small><pre>" + html.escape(log) + "</pre></small>" except: msg += _("Have you installed latex and dvipng/dvisvgm?") return msg # setup q/a filter addHook("mungeQA", mungeQA) #This hook is called collection._renderQA. See mungeQA comment to know #the parameters
note["Pinyin"] = note["Pinyin"].rstrip() return True def on_focus_lost(flag, note, _fidx): """ Takes filled in hanzi field and matches empty fields with their respective information """ if "Chinese" not in note.model()['name']: return flag if not note["Hanzi"] or note["Pinyin"] or note["Meaning"]: return flag cursor = CONN.cursor() cursor.execute("SELECT * FROM entries WHERE simplified = ? LIMIT 1", (note["Hanzi"], )) entry = cursor.fetchone() if entry is None: cursor.close() return multiple_hanzi(note, flag) note["Pinyin"] = entry[2] note["Meaning"] = entry[3].replace("/", "<br>") cursor.close() return True addHook('editFocusLost', on_focus_lost)
print(obj) item = obj.form.menu_Cards def register_action(*actArgs, trigger): "Automatically handles cleanup registration for reloading" action = item.addAction(*actArgs) prev_actions.append((item, action)) action.triggered.connect(lambda _: trigger(obj)) return action o_card = register_action("Use as ordering card", trigger=search_ordering_card) o_card.setShortcut(QKeySequence("Ctrl+Shift+O")) c_card = register_action("Confirm matching card", trigger=confirm_matching_card) if get_reload_enabled(): rl_card = register_action("Reload Card_Transformer Extension", trigger=reload_extension) rl_card.setShortcut(QKeySequence("Ctrl+Shift+E")) # clear previous menu hook to prevent duplicate menu items being added across browser sessions try: remHook("browser.setupMenus", prev_menu_hook) except NameError: prev_menu_hook = None addHook("browser.setupMenus", setup_menus) prev_menu_hook = setup_menus
random.choice(string.ascii_letters + string.digits) for n in range(32) ]) + '"' def randomizeId(s): return re.sub(r' +id *= *[\'"]*([^ \'">]+)[\'"]*', getRandomId, s, 0, re.IGNORECASE) out = "" for cid in ids: c = self.col.getCard(cid) out += '<div class="Card">\n' out += '<div class="Question">\n' + esc(c.q()) + "\n</div>\n" out += '<div class="Answer">\n' + esc(c.a()) + "\n</div>\n" out += "</div><!-- Card -->\n\n" out = self.htmlBefore + out + self.htmlAfter file.write(out.encode("utf-8")) def addMyExporter(exps): def theid(obj): return ("%s (*%s)" % (obj.key, obj.ext), obj) exps.append(theid(MyTextCardExporter)) addHook("exportersList", addMyExporter)
def accept(self): self.exporter.includeSched = (self.frm.includeSched.isChecked()) self.exporter.includeMedia = (self.frm.includeMedia.isChecked()) self.exporter.includeTags = (self.frm.includeTags.isChecked()) if not self.frm.deck.currentIndex(): self.exporter.did = None else: name = self.decks[self.frm.deck.currentIndex()] self.exporter.did = self.col.decks.id(name) if (self.isApkg and self.exporter.includeSched and not self.exporter.did): verbatim = True # it's a verbatim apkg export, so place on desktop instead of # 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 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 # Get deck name and remove invalid filename characters deck_name = self.decks[self.frm.deck.currentIndex()] deck_name = re.sub('[\\\\/?<>:*|"^]', '_', deck_name) filename = os.path.join( aqt.mw.pm.base, u'{0}{1}'.format(deck_name, self.exporter.ext)) while 1: file = getSaveFile(self, _("Export"), "export", self.exporter.key, self.exporter.ext, fname=filename) if not file: return if checkInvalidFilename(os.path.basename(file), dirsep=False): continue break self.hide() if file: self.mw.progress.start(immediate=True) try: f = open(file, "wb") f.close() except (OSError, IOError), e: showWarning(_("Couldn't save file: %s") % unicode(e)) else: os.unlink(file) exportedMedia = lambda cnt: self.mw.progress.update( label=ngettext("Exported %d media file", "Exported %d media files", cnt) % cnt) addHook("exportedMediaFiles", exportedMedia) self.exporter.exportInto(file) remHook("exportedMediaFiles", exportedMedia) if verbatim: 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 if self.isTextNote: msg = ngettext( "%d note exported.", "%d notes exported.", self.exporter.count) % self.exporter.count else: msg = ngettext( "%d card exported.", "%d cards exported.", self.exporter.count) % self.exporter.count tooltip(msg, period=period) finally:
return showWarning( r"""<p>Please install <a href='https://mpv.io'>mpv</a>.</p> On Windows download mpv and either update PATH environment variable or put mpv.exe in Anki installation folder (C:\Program Files\Anki).""", parent=mw) else: _player(path) def _stopPlayer(): global p if p != None and p.poll() is None: p.kill() addHook("unloadProfile", _stopPlayer) atexit.register(_stopPlayer) def clearExternalQueue(): global _queueEraser _stopPlayer() _queueEraser() _player = s._player s._player = queueExternal _queueEraser = s._queueEraser s._queueEraser = clearExternalQueue
clayout.forms[-1]['pform'].frontWeb.setLinkHandler(simple_link_handler) clayout.forms[-1]['pform'].backWeb.setLinkHandler(simple_link_handler) def add_preview_link_handler(browser): u"""Make sure we play the files from the preview window.""" browser._previewWeb.setLinkHandler(simple_link_handler) def reduce_format_qa(self, text): u"""Remove elements with a given class before displaying.""" soup = BeautifulSoup(text) for hide in soup.findAll( True, {'class': re.compile('\\b' + hide_class_name + '\\b')}): hide.extract() return original_format_qa(self, unicode(soup)) original_review_link_handler = Reviewer._linkHandler Reviewer._linkHandler = review_link_handler_wrapper original_format_qa = DataModel.formatQA DataModel.formatQA = reduce_format_qa old_css = Card.css Card.css = svg_css addHook("mungeQA", play_button_filter) Browser._openPreview = wrap(Browser._openPreview, add_preview_link_handler) CardLayout.addTab = wrap(CardLayout.addTab, add_clayout_link_handler)
mw.reset() mw.progress.finish() tooltip(_("""Prefix removed.""")) def setupMenu(browser): a = QAction("Add prefix", browser) shortcut = getConfig("Shortcut: Add prefix", "Ctrl+Alt+P") if shortcut: a.setShortcut(QKeySequence(shortcut)) a.triggered.connect(lambda: onAddPrefix(browser)) browser.form.menuEdit.addAction(a) shortcut = getConfig("Shortcut: Remove prefix", "Ctrl+Shift+Alt+P") if shortcut: a.setShortcut(QKeySequence(shortcut)) a = QAction("Remove prefix", browser) a.setShortcut(QKeySequence("Ctrl+Shift+Alt+P")) a.triggered.connect(lambda: onRemovePrefix(browser)) browser.form.menuEdit.addAction(a) def onAddPrefix(browser): addPrefix(browser.selectedCards()) def onRemovePrefix(browser): removePrefix(browser.selectedCards()) addHook("browser.setupMenus", setupMenu)
def __init__(self): addHook('setupEditorButtons', self.setupButton) addHook('loadNote', self.updateButton) addHook('editFocusLost', self.onFocusLost)
""" returns the modules base directory """ directory = os.path.dirname(os.path.abspath(__file__)) results = directory.split('\\') tail = results[-1].lower() while tail != 'vocabolaudioscraper': directory = os.path.dirname(os.path.abspath(directory)) results = directory.split('\\') tail = results[-1].lower() return directory def addEditorButton(buttons, editor): """ creates a new button returns new set of buttons """ editor._links['data'] = get_data path = get_base_directory() icon = path + '/resources/icon.png' return buttons + [editor._addButton(icon, 'data', 'get audio')] addHook('setupEditorButtons', addEditorButton)
def reduce_format_qa(self, text): u"""Remove elements with a given class before displaying.""" soup = BeautifulSoup(text, 'html.parser') for hide in soup.findAll( True, {'class': re.compile('\\b' + hide_class_name + '\\b')}): hide.extract() return original_format_qa(self, unicode(soup)) def copy_arrow(): u"""Copy the image file to the collection.""" if not os.path.exists( os.path.join(mw.col.media.dir(), collection_arrow_name)): shutil.copy( os.path.join(mw.pm.addonFolder(), 'color_icons', original_arrow_name), collection_arrow_name) original_review_link_handler = Reviewer._linkHandler Reviewer._linkHandler = review_link_handler_wrapper original_format_qa = DataModel.formatQA DataModel.formatQA = reduce_format_qa addHook("mungeQA", play_button_filter) Browser._openPreview = wrap(Browser._openPreview, add_preview_link_handler) CardLayout.addTab = wrap(CardLayout.addTab, add_clayout_link_handler) addHook("profileLoaded", copy_arrow)