def test_and_dehashilate(): if not test_names(): showInfo('No hashes found in cards. Have a nice day.') return if not askUser('Go ahead?\nThis cannot be undone!\nUse at your own risk!\n' 'Backup your collection before continuing!'): return if not askUser('Click on "No".\n' 'Clicking on "Yes" will probably mess up your collection.\n' 'You will have to fix it yourself!', defaultno=True): return dehashilate()
def add_nids_to_all(): """Add note id to all empty fields with the right names. Iterate over all notes and add the nid minus 1’300’000’000’000. The subtraction is done mostly for aesthetical reasons. """ if not askUser( _("Add note id to all “{fn}” fields?".format( fn=config["NoteIdFieldName"]))): return # Maybe there is a way to just select the notes which have a nid # field. But this should work and efficency isn't too much of an # issue. nids = mw.col.db.list("select id from notes") # Iterate over the cards for nid in progress(nids, _("Adding note ids."), _("Stop that!")): n = mw.col.getNote(nid) # Go over the fields ... for name in mw.col.models.fieldNames(n.model()): # ... and the target field names .. if name == config["NoteIdFieldName"]: # Check if target is empty if not n[name]: n[name] = str(nid - int(15e11)) n.flush() mw.reset()
def addNote(self, note): note.model()["did"] = self.deckChooser.selectedId() ret = note.dupeOrEmpty() if ret == 1: showWarning(_("The first field is empty."), help="AddItems#AddError") return if "{{cloze:" in note.model()["tmpls"][0]["qfmt"]: if not self.mw.col.models._availClozeOrds(note.model(), note.joinedFields(), False): if not askUser( _("You have a cloze deletion note type " "but have not made any cloze deletions. Proceed?") ): return cards = self.mw.col.addNote(note) if not cards: showWarning( _( """\ The input you have provided would make an empty \ question on all cards.""" ), help="AddItems", ) return self.addHistory(note) self.mw.requireReset() return note
def onFieldToTags(self, _): """Main function""" nids = self.selectedNotes() count = len(nids) if not nids: tooltip("Please select some cards.") return fields = sorted(find.fieldNames(self.col, downcase=False)) if not fields: tooltip("No fields found." "Something might be wrong with your collection") return field = getField(self, fields) if not field: return q = ("Are you sure you want to convert the <b>'{}'</b> field " "to tags in <b>{}</b> selected notes?".format(field, count)) ret = askUser(q, parent=self, title="Please confirm your choice") if not ret: return self.mw.checkpoint("Find and Replace") self.mw.progress.start() self.model.beginReset() edited = self.fieldToTags(nids, field) self.model.endReset() self.mw.progress.finish() tooltip("{} out of {} notes updated.".format(edited, count))
def add_nids_to_all(): """ Add note id to all empty fields with the right names. Iterate over all notes and add the nid """ if not askUser(_(u"Add note id to all 'Note ID' fields?")): return # Maybe there is a way to just select the notes which have a nid # field. But this should work and efficency isn't too much of an # issue. nids = mw.col.db.list("select id from notes") # Iterate over the cards for nid in progress(nids, _(u"Adding note ids."), _(u"Stop that!")): n = mw.col.getNote(nid) # Go over the fields ... for name in mw.col.models.fieldNames(n.model()): # ... and the target field names .. for f in id_fields: # ... and compare the two if f == name.lower(): # Check if target is empty if not n[name]: n[name] = str(nid) n.flush() mw.reset()
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 file = os.path.join(QDesktopServices.storageLocation( QDesktopServices.DesktopLocation), "collection.apkg") if os.path.exists(file): if not askUser( _("%s already exists on your desktop. Overwrite it?")% "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) self.exporter.exportInto(file) if verbatim: msg = _("A file called collection.apkg was saved on your desktop.") period = 5000 else: period = 3000 msg = ngettext("%d card exported.", "%d cards exported.", \ self.exporter.count) % self.exporter.count tooltip(msg, period=period) finally:
def onRemoveTab(self, idx): if not askUser(_("Remove template and all its cards?")): return if not self.mm.remTemplate(self.model, self.cards[idx].template()): return showWarning(_("""\ Removing this card would cause one or more notes to be deleted. \ Please create a new card first.""")) self.redraw()
def display_next_tip(): (tip, link) = chinese_support_config.get_next_tip() if tip: if link: if askUser(tip): openLink(link) else: showInfo(tip)
def _updateSchedVer(self, wantNew): haveNew = self.mw.col.schedVer() == 2 # nothing to do? if haveNew == wantNew: return if haveNew and not wantNew: if not askUser(_("This will reset any cards in learning, clear filtered decks, and change the scheduler version. Proceed?")): return self.mw.col.changeSchedulerVer(1) return if not askUser(_("The experimental scheduler could cause incorrect scheduling. Please ensure you have read the documentation first. Proceed?")): return self.mw.col.changeSchedulerVer(2)
def setChildren(self): if not askUser(_("Set all decks below %s to this option group?") % self.deck["name"]): return for did in self.childDids: deck = self.mw.col.decks.get(did) deck["conf"] = self.deck["conf"] self.mw.col.decks.save(deck) tooltip(ngettext("%d deck updated.", "%d decks updated.", len(self.childDids)) % len(self.childDids))
def setChildren(self): if not askUser( _("Set all decks below %s to this option group?") % self.deck['name']): return for did in self.childDids: deck = self.mw.col.decks.get(did) deck['conf'] = self.deck['conf'] self.mw.col.decks.save(deck) tooltip(_("%d decks updated.") % len(self.childDids))
def onRemoveTab(self, idx): if len(self.model['tmpls']) < 2: return showInfo(_("At least one card is required.")) if not askUser(_("Remove all cards of this type?")): return if not self.mm.remTemplate(self.model, self.cards[idx].template()): return showWarning(_("""\ Removing this card type would cause one or more notes to be deleted. \ Please create a new card type first.""")) self.redraw()
def onFullSync(self): if not askUser(_("""\ If you proceed, you will need to choose between a full download or full \ upload, overwriting any changes either here or on AnkiWeb. Proceed?""")): return self.hideSchemaMsg = True self.col.modSchema() self.col.setMod() self.hideSchemaMsg = False self.onSync()
def deleteUnused(self, unused, diag): if not askUser( _("Delete unused media? This operation can not be undone.")): return mdir = self.col.media.dir() for f in unused: path = os.path.join(mdir, f) os.unlink(path) tooltip(_("Deleted.")) diag.close()
def deleteUnused(self, unused, diag): if not askUser( _("Delete unused media?")): return mdir = self.col.media.dir() for f in unused: path = os.path.join(mdir, f) send2trash(path) tooltip(_("Deleted.")) diag.close()
def onDelete(self): selected = self.selectedAddons() if not selected: return if not askUser(_("Delete the %(num)d selected add-ons?") % dict(num=len(selected))): return for dir in selected: self.mgr.deleteAddon(dir) self.redrawAddons()
def accept(self): if not self.saveConf(): return if not self.mw.col.sched.rebuildDyn(): if askUser(_("""\ The provided search did not match any cards. Would you like to revise \ it?""")): return self.mw.reset() QDialog.accept(self)
def onOpenBackup(self): if not askUser(_("""\ Replace your collection with an earlier backup?"""), msgfunc=QMessageBox.warning, defaultno=True): return def doOpen(path): self._openBackup(path) getFile(self.profileDiag, _("Revert to backup"), cb=doOpen, filter="*.colpkg", dir=self.pm.backupFolder())
def _delete(self, did): if str(did) == '1': return showWarning(_("The default deck can't be deleted.")) self.mw.checkpoint(_("Delete Deck")) deck = self.mw.col.decks.get(did) if deck['dyn'] or askUser(_("""\ Are you sure you wish to delete all of the cards in %s?""")%deck['name']): self.mw.progress.start(immediate=True) self.mw.col.decks.rem(did, True) self.mw.progress.finish() self.show()
def on_fix_button(): if not askUser(question, defaultno=True): return media_dir = mw.col.media.dir() files = get_image_occlusion_files(media_dir) fixed = fix_files(files) showInfo("Done. {}/{} files needed fixing." "<br><br>Please consider upgrading to " "<a href='https://ankiweb.net/shared/info/1111933094'>" "Image Occlusion Enhanced</a> to avoid issues like these " "in the future".format(fixed, len(files)))
def fill_sounds(collection, view_key): if view_key == "deckBrowser": return showInfo(u"Please first select one of your decks.") if not(askUser("<div>This will update the <i>Sound</i> fields in the current deck, if they exist and are empty, using the selected speech engine.</div>\n\n<div>Please back-up your Anki deck first!</div>\n\n<div><b>Continue?</b></div>")): return False query_str = "deck:current" d_scanned = 0 d_has_fields = 0 d_already_had_sound = 0 d_success = 0 d_failed = 0 notes = Finder(collection).findNotes(query_str) mw.progress.start(immediate=True, min=0, max=len(notes)) for noteId in notes: d_scanned += 1 note = collection.getNote(noteId) note_dict = dict(note) # edit_function routines require a dict _hf_s = has_field(Sound_fields, note_dict) _hf_sm = has_field(Sound_Mandarin_fields, note_dict) _hf_sc = has_field(Sound_Cantonese_fields, note_dict) if (_hf_s or _hf_sm or _hf_sc) and has_field(Hanzi_fields, note_dict): d_has_fields += 1 hanzi = get_any(Hanzi_fields, note_dict) if get_any(Sound_fields, note_dict) or get_any(Sound_Mandarin_fields, note_dict) or get_any(Sound_Cantonese_fields, note_dict): d_already_had_sound += 1 else: msg_string = "<b>Processing:</b> %(hanzi)s<br><b>Updated:</b> %(d_success)d notes<br><b>Failed:</b> %(d_failed)d notes"% {"hanzi":cleanup(no_html(get_any(Hanzi_fields, note_dict))), "d_success":d_success, "d_failed":d_failed} mw.progress.update(label=msg_string, value=d_scanned) s, f = update_all_Sound_fields(hanzi, note_dict) d_success += s d_failed += f # write back to note from dict and flush for f in Sound_fields + Sound_Mandarin_fields + Sound_Cantonese_fields: if note_dict.has_key(f) and note_dict[f] <> note[f]: note[f] = note_dict[f] note.flush() mw.progress.finish() msg_string = ''' %(d_success)d new pronunciations downloaded %(d_failed)d downloads failed %(have)d/%(d_has_fields)d notes now have pronunciation ''' % {"d_success":d_success, "d_failed":d_failed, "have":d_already_had_sound+d_success, "d_has_fields":d_has_fields} if d_failed>0: msg_string = msg_string+"\n\nTTS is taken from an on-line source. It may not always be fully responsive. Please check your network connexion, or retry later." showInfo(msg_string)
def deleteTemplate(self): if len (self.model.templates) < 2: ui.utils.showWarning( _("Please add a new template first."), parent=self) return if not askUser( _("Delete this template and all cards that use it?")): return self.model.delTemplate(self.template) self.updateTemplates()
def onDelete(self): if len(self.model["flds"]) < 3: return showWarning(_("Notes require at least two fields.")) if not askUser(_("Delete field?")): return f = self.model["flds"][self.form.fieldList.currentRow()] self.mw.progress.start() self.mm.remField(self.model, f) self.mw.progress.finish() self.fillFields() self.form.fieldList.setCurrentRow(0)
def getFile(self, pathName): if os.path.exists(pathName): ok = askUser(_("The file \n%s \nalready exists. Overwrite it?") % pathName) if not ok: return None try: file = open(pathName, "w") except: file = None showWarning(_("Could not open the file \n%s. \n") % pathName) return file
def onRemProfile(self): profs = self.pm.profiles() if len(profs) < 2: return showWarning(_("There must be at least one profile.")) # sure? if not askUser(_("""\ All cards, notes, and media for this profile will be deleted. \ Are you sure?"""), msgfunc=QMessageBox.warning, defaultno=True): return self.pm.remove(self.pm.name) self.refreshProfilesList()
def copy_all(): # Find the models that have the right name and fields; faster than # checking every note if not askUser("Fill with kanji diagrams references?"): return models = [m for m in mw.col.models.all() if model_is_correct_type(m)] # Find the notes in those models and give them kanji for model in models: for nid in mw.col.models.nids(model): add_kanji(mw.col.getNote(nid)) tooltip("Done copying colorized kanji diagrams!")
def onDelete(self): if len(self.models) < 2: showInfo(_("Please add another model first."), parent=self) return if not askUser( _("Delete this model and all its cards?"), parent=self): return self.deck.delModel(self.model.id) self.model = None self.updateModelsList()
def onSchemaMod(self, arg): # if triggered in sync, make sure we don't use the gui if not self.inMainThread(): return True # if from the full sync menu, ignore if self.hideSchemaMsg: return True return askUser(_("""\ The requested change will require a full upload of the database when \ you next synchronize your collection. If you have reviews or other changes \ waiting on another device that haven't been synchronized here yet, they \ will be lost. Continue?"""))
def onDelete(self): if len(self.models) < 2: showInfo(_("Please add another note type first."), parent=self) return if not askUser( _("Delete this note type and all its cards?"), parent=self): return self.mm.rem(self.model) self.model = None self.updateModelsList()
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): addKanji(mw.col.getNote(nid)) showInfo("Done regenerating colorized kanji diagrams!")
def reset_threshold(): if askUser("Really reset threshold?"): mw.pm.profile["reset_ease_mod__last_run"] = 0 tooltip("""Reset to zero.""")
def reject(self) -> None: if self.change_tracker.changed(): if not askUser("Discard changes?"): return self.cleanup() return QDialog.reject(self)
def reject(self) -> None: if self.change_tracker.changed(): if not askUser(tr(TR.CARD_TEMPLATES_DISCARD_CHANGES)): return self.cleanup() return QDialog.reject(self)
def sync_duolingo(): model = get_duolingo_model(mw) if not model: showWarning("Could not find or create Duolingo Sync note type.") return note_ids = mw.col.findNotes("tag:duolingo_sync") notes = mw.col.db.list("select flds from notes where id in {}".format( ids2str(note_ids))) gids_to_notes = {splitFields(note)[0]: note for note in notes} try: username, password = duolingo_dialog(mw) except TypeError: return if username and password: try: mw.progress.start(immediate=True, label="Logging in...") login_thread = DuolingoThread(target=Duolingo, args=(username, password)) login_thread.start() while login_thread.is_alive(): time.sleep(0.02) mw.progress.update() lingo = login_thread.join() vocabulary_thread = DuolingoThread(target=lingo.get_vocabulary) vocabulary_thread.start() mw.progress.update(label="Retrieving vocabulary...") while vocabulary_thread.is_alive(): time.sleep(0.02) mw.progress.update() vocabulary_response = vocabulary_thread.join() except LoginFailedException: showWarning(""" <p>Logging in to Duolingo failed. Please check your Duolingo credentials.</p> <p>Having trouble logging in? You must use your <i>Duolingo</i> username and password. You <i>can't</i> use your Google or Facebook credentials, even if that's what you use to sign in to Duolingo.</p> <p>You can find your Duolingo username at <a href="https://www.duolingo.com/settings">https://www.duolingo.com/settings</a> and you can create or set your Duolingo password at <a href="https://www.duolingo.com/settings/password">https://www.duolingo.com/settings/password</a>.</p> """) return except requests.exceptions.ConnectionError: showWarning( "Could not connect to Duolingo. Please check your internet connection." ) return finally: mw.progress.finish() language_string = vocabulary_response["language_string"] vocabs = vocabulary_response["vocab_overview"] did = mw.col.decks.id("Default") mw.col.decks.select(did) deck = mw.col.decks.get(did) deck["mid"] = model["id"] mw.col.decks.save(deck) words_to_add = [ vocab for vocab in vocabs if vocab["id"] not in gids_to_notes ] if not words_to_add: showInfo( "Successfully logged in to Duolingo, but no new words found in {} language." .format(language_string)) elif askUser("Add {} notes from {} language?".format( len(words_to_add), language_string)): word_chunks = [ words_to_add[x:x + 50] for x in range(0, len(words_to_add), 50) ] mw.progress.start( immediate=True, label="Importing from Duolingo...", max=len(words_to_add), ) notes_added = 0 for word_chunk in word_chunks: translations = lingo.get_translations( [vocab["word_string"] for vocab in word_chunk]) for vocab in word_chunk: n = mw.col.newNote() # Update the underlying dictionary to accept more arguments for more customisable cards n._fmap = defaultdict(str, n._fmap) n["Gid"] = vocab["id"] n["Gender"] = vocab["gender"] if vocab["gender"] else "" n["Source"] = "; ".join(translations[vocab["word_string"]]) n["Target"] = vocab["word_string"] n["Pronunciation"] = vocab["normalized_string"].strip() n["Target Language"] = language_string n.addTag(language_string) n.addTag("duolingo_sync") if vocab["pos"]: n.addTag(vocab["pos"]) if vocab["skill"]: n.addTag(vocab["skill"].replace(" ", "-")) mw.col.addNote(n) notes_added += 1 mw.progress.update(value=notes_added) showInfo("{} notes added".format(notes_added)) mw.moveToState("deckBrowser") mw.progress.finish()
def onSchemaMod(self, arg): return askUser(_("""\ The requested change will require a full upload of the database when \ you next synchronize your collection. If you have reviews or other changes \ waiting on another device that haven't been synchronized here yet, they \ will be lost. Continue?"""))
def canClose(self): has_data = self.form.pteText.toPlainText() or self.form.pteNotes.toPlainText() if (not has_data or askUser(_("Close and lose current input?"))): return True return False
def reject(self): if self.change_tracker.changed(): if not askUser("Discard changes?"): return QDialog.reject(self)
def _forExistingCards(prompt, funcForExistingCards): if not askUser(_(prompt)): return cloze = mw.col.models.byName("Cloze") nids = mw.col.models.nids(cloze) funcForExistingCards(nids)
def _onTreeFavDelete(self, item): for idx in self.selectedIndexes(): itm = idx.internalPointer() if mw.col.conf['savedFilters'].get(itm.favname) and \ askUser(_("Remove %s from your saved searches?") % itm.favname): del mw.col.conf['savedFilters'][itm.favname]
def on_import(self): dict_nm = '' if self.builder: try: mdx_dict = readmdict.MDX(self.mdx, only_header=True) self.builder._encoding = mdx_dict._encoding except MemoryError: showInfo(_trans("MDX MEMORY ERROR"), self, type="warning", title=_trans("ANKINDLE")) return except TypeError: showInfo(_trans("MDX TYPE ERROR"), self, type="warning", title=_trans("ANKINDLE")) return dict_nm = os.path.splitext(os.path.basename(mdx_dict._fname))[0] else: ret = askUser(_trans("ALERT FOR MISSING MDX"), self, defaultno=False, title=_trans("ANKINDLE")) if not ret: return total_new = 0 total_dup = 0 for i, _ in enumerate(self.yield_one_word()): (id, word, stem, lang, added_tm, usage, title, authors, category) = _ # region save new cards try: note = notes.Note(mw.col, mw.col.models.models[str(self.model['id'])]) except KeyError: continue note.model()['did'] = self.deck['id'] def update_note(_note): qry_word = stem if stem else word if word else '' _usage = self.adapt_to_anki( usage.replace(word, u"<b>%s</b>" % word)) if usage else '' try: _id_in_field = re.sub("[^0-9a-zA-Z]", "", qry_word + usage).strip().upper() except TypeError: return False _note.fields[_note._fieldOrd( 'id')] = _id_in_field if _id_in_field else '' _note.fields[_note._fieldOrd('word')] = word if word else '' _note.fields[_note._fieldOrd('stem')] = stem if stem else '' _note.fields[_note._fieldOrd('lang')] = lang if lang else '' _note.fields[_note._fieldOrd( 'creation_tm')] = added_tm if added_tm else '' _note.fields[_note._fieldOrd( 'usage')] = _usage if _usage else '' _note.fields[_note._fieldOrd('title')] = title if title else '' _note.fields[_note._fieldOrd( 'authors')] = authors if authors else '' _note.fields[_note._fieldOrd('mdx_dict')] = self.get_html( qry_word) try: _note.fields[_note._fieldOrd('mdx_name')] = dict_nm except KeyError: pass return True if update_note(note): if note.dupeOrEmpty() != 2: mw.col.addNote(note) total_new += 1 else: total_dup += 1 mw.col.autosave() # endregion # copy css files if self.mdx: mdx_dict_dir = os.path.split(self.mdx)[0] include_mdx_extras = ['.CSS', '.JS'] for root, dirs, files in os.walk(mdx_dict_dir): for _mfile in [ css for css in files if os.path.splitext(css) [1].strip().upper() in include_mdx_extras ]: _nfile = _mfile if _mfile in self.missed_css: _nfile = "_" + _mfile shutil.copy(os.path.join(root, _mfile), _nfile) mw.moveToState("deckBrowser") showText( _trans("CREATED AND DUPLICATES") % (total_new, total_dup), self)
def fill_pinyin(): prompt = ''' <div>This will update the <i>Pinyin</i> (or <i>Transcription</i>), <i>Color</i> and <i>Ruby</i> fields in the current deck, if they exist.</div> <div><i>Pinyin</i> and <i>Transcription</i> will be filled if empty. Otherwise, their colorization and accentuation will be refreshed as needed.</div> <div>Please back-up your Anki deck first!</div> <div><b>Continue?</b></div> ''' if not askUser(prompt): return query_str = 'deck:current' d_scanned = 0 d_has_fields = 0 d_added_pinyin = 0 d_updated = 0 notes = Finder(mw.col).findNotes(query_str) mw.progress.start(immediate=True, min=0, max=len(notes)) for noteId in notes: d_scanned += 1 note = mw.col.getNote(noteId) note_dict = dict(note) _hf_t = has_field(config['fields']['transcription'], note_dict) _hf_py = has_field(config['fields']['pinyin'], note_dict) _hf_pytw = has_field(config['fields']['pinyinTaiwan'], note_dict) _hf_cant = has_field(config['fields']['cantonese'], note_dict) _hf_bpmf = has_field(config['fields']['bopomofo'], note_dict) if ((_hf_t or _hf_py or _hf_pytw or _hf_cant or _hf_bpmf) and has_field(config['fields']['hanzi'], note_dict)): d_has_fields += 1 msg = ''' <b>Processing:</b> %(hanzi)s<br> <b>Filled pinyin:</b> %(pinyin)d notes<br> <b>Updated: </b>%(updated)d fields''' % { 'hanzi': sanitize_hanzi(note_dict), 'pinyin': d_added_pinyin, 'updated': d_updated } mw.progress.update(label=msg, value=d_scanned) hanzi = get_first(config['fields']['hanzi'], note_dict) results = 0 if _hf_t: results += update_Transcription_fields(hanzi, note_dict) if _hf_py: results += update_Pinyin_fields(hanzi, note_dict) if _hf_pytw: results += update_PinyinTW_fields(hanzi, note_dict) if _hf_cant: results += update_Cantonese_fields(hanzi, note_dict) if _hf_bpmf: results += update_bopomofo(hanzi, note_dict) if results != 0: d_added_pinyin += 1 update_all_Color_fields(hanzi, note_dict) update_all_Ruby_fields(hanzi, note_dict) def write_back(fields): num_updated = 0 for f in fields: if f in note_dict and note_dict[f] != note[f]: note[f] = note_dict[f] num_updated += 1 return num_updated d_updated += write_back(config['fields']['transcription']) d_updated += write_back(config['fields']['pinyin']) d_updated += write_back(config['fields']['pinyinTaiwan']) d_updated += write_back(config['fields']['cantonese']) d_updated += write_back(config['fields']['bopomofo']) d_updated += write_back(config['fields']['color']) d_updated += write_back(config['fields']['colorPinyin']) d_updated += write_back(config['fields']['colorPinyinTaiwan']) d_updated += write_back(config['fields']['colorCantonese']) d_updated += write_back(config['fields']['colorBopomofo']) d_updated += write_back(config['fields']['ruby']) d_updated += write_back(config['fields']['rubyPinyin']) d_updated += write_back(config['fields']['rubyPinyinTaiwan']) d_updated += write_back(config['fields']['rubyCantonese']) d_updated += write_back(config['fields']['rubyBopomofo']) note.flush() mw.progress.finish() msg = ''' <b>Processing:</b> %(hanzi)s<br> <b>Filled pinyin:</b> %(pinyin)d notes<br> <b>Updated: </b>%(updated)d fields''' % { 'hanzi': sanitize_hanzi(note_dict), 'pinyin': d_added_pinyin, 'updated': d_updated } showInfo(msg)
def bulk_fill_defs(): prompt = PROMPT_TEMPLATE.format( field_names='<i>definition</i> and <i>alternative</i>', extra_info='') progress_msg_template = ''' <b>Processing:</b> %(hanzi)s<br> <b>Chinese notes:</b> %(has_fields)d<br> <b>Translated:</b> %(filled)d<br> <b>Failed:</b> %(failed)d''' fields = config.get_fields(['english', 'german', 'french']) if not askUser(prompt): return n_targets = 0 d_success = 0 d_failed = 0 failed_hanzi = [] note_ids = Finder(mw.col).findNotes('deck:current') mw.progress.start(immediate=True, min=0, max=len(note_ids)) for i, nid in enumerate(note_ids): note = mw.col.getNote(nid) copy = dict(note) hanzi = get_hanzi(copy) if has_any_field(copy, fields) and hanzi: n_targets += 1 if all_fields_empty(copy, fields): result = fill_all_defs(hanzi, copy) if result: d_success += 1 else: d_failed += 1 if d_failed < 20: failed_hanzi += [hanzi] msg = progress_msg_template % { 'hanzi': hanzi, 'has_fields': n_targets, 'filled': d_success, 'failed': d_failed, } mw.progress.update(label=msg, value=i) save_note(note, copy) msg = ''' <b>Translation complete</b><br> <b>Chinese notes:</b> %(has_fields)d<br> <b>Translated:</b> %(filled)d<br> <b>Failed:</b> %(failed)d''' % { 'has_fields': n_targets, 'filled': d_success, 'failed': d_failed, } if d_failed > 0: msg += ( '<div>Translation failures may come either from connection issues ' "(if you're using an online translation service), or because some " 'words are not it the dictionary (for local dictionaries).</div>' '<div>The following notes failed: ' + ', '.join(failed_hanzi) + '</div>') mw.progress.finish() showInfo(msg)
def javaScriptConfirm(self, frame: Any, text: str) -> bool: return askUser(text)
def onRem(self, path): if not askUser(_("Delete %s?") % os.path.basename(path)): return os.unlink(path) self.rebuildAddonsMenu() showInfo(_("Deleted. Please restart Anki."))
def _onTreeFavDelete(self, item): act = mw.col.conf['savedFilters'].get(item.favname) if not act: return if askUser(_("Remove %s from your saved searches?") % item.favname): del mw.col.conf['savedFilters'][item.favname]
def reject(self) -> None: if self.change_tracker.changed(): if not askUser(tr.card_templates_discard_changes()): return self.cleanup() return QDialog.reject(self)
def afterSave(): ok = (self.editor.fieldsAreBlank() or askUser(_("Close and lose current input?"))) if ok: onOk()
def afterSave(): ok = self.editor.fieldsAreBlank(self.previousNote) or askUser( _("Close and lose current input?"), defaultno=True) if ok: onOk()
def canClose(self): if (self.forceClose or self.editor.fieldsAreBlank() or askUser(_("Close and lose current input?"))): return True return False
def fill_sounds(): prompt = """<div>This will update the <i>Sound</i> fields in the current deck, if they exist and are empty, using the selected speech engine.</div> <div>Please back-up your Anki deck first!</div> <div>(Please also note that there will be a 5 second delay between each sound request, to reduce burden on the server. This may therefore take a while.)</div> <div><b>Continue?</b></div>""" if not askUser(prompt): return False query_str = "deck:current" d_scanned = 0 d_has_fields = 0 d_already_had_sound = 0 d_success = 0 d_failed = 0 notes = Finder(mw.col).findNotes(query_str) mw.progress.start(immediate=True, min=0, max=len(notes)) for noteId in notes: d_scanned += 1 note = mw.col.getNote(noteId) note_dict = dict(note) # edit_function routines require a dict if has_field(config["fields"]["sound"], note_dict) and has_field( config["fields"]["hangul"], note_dict): d_has_fields += 1 hangul = get_any(config["fields"]["hangul"], note_dict) if get_any(config["fields"]["sound"], note_dict): d_already_had_sound += 1 else: msg_string = ("<b>Processing:</b> {hangul:s}<br>" "<b>Updated:</b> {d_success:d} notes<br>" "<b>Failed:</b> {d_failed:d} notes").format( hangul=cleanup( no_html( get_any(config["fields"]["hangul"], note_dict))), d_success=d_success, d_failed=d_failed, ) mw.progress.update(label=msg_string, value=d_scanned) s, f = update_Sound_fields(hangul, note_dict) d_success += s d_failed += f # write back to note from dict and flush for f in config["fields"]["sound"]: if f in note_dict and note_dict[f] != note[f]: note[f] = note_dict[f] note.flush() sleep(5) mw.progress.finish() msg_string = """ {d_success:d} new pronunciations downloaded {d_failed:d} downloads failed {have:d}/{d_has_fields:d} notes now have pronunciation """.format( d_success=d_success, d_failed=d_failed, have=d_already_had_sound + d_success, d_has_fields=d_has_fields, ) if d_failed > 0: msg_string = msg_string + ("\n\nTTS is taken from an on-line source. " "It may not always be fully responsive. " "Please check your network connexion, " "or retry later.\n\nIf failures persist, " "please set Korean Support to debug mode " "and submit a bug report from the help " "menu.") showInfo(msg_string)
def afterSave() -> None: ok = self.editor.fieldsAreBlank(self._last_added_note) or askUser( tr.adding_close_and_lose_current_input(), defaultno=True) if ok: onOk()
def fill_translation(collection, view_key): if view_key == "deckBrowser": return showInfo(u"First select one of your decks") if not (askUser( "<div>This will update the <i>Meaning</i>, <i>Mean Word</i>, and <i>Also Written</i> fields in the current deck, if they exist and are empty.</div><b>Learning tip:</b><div>Automatic dictionary lookup tends to produce very long text, often with multiple translations.</div>\n\n<div>For more effective memorization, it's highly recommended to trim them down to just a few words, only one meaning, and possibly add some mnemonics.</div>\n\n<div>Dictionary lookup is simply meant as a way to save you time when typing; please consider editing each definition by hand when you're done.</div>\n\n<div>Please back-up your Anki deck first!</div>\n\n<div><b>Continue?</b></div>" )): return False query_str = "deck:current" d_scanned = 0 d_has_fields = 0 d_success = 0 d_failed = 0 failed_hanzi = [] notes = Finder(collection).findNotes(query_str) mw.progress.start(immediate=True, min=0, max=len(notes)) for noteId in notes: d_scanned += 1 note = collection.getNote(noteId) note_dict = dict(note) # edit_function routines require a dict _hf_m = has_field(Meaning_fields, note_dict) _hf_e = has_field(English_fields, note_dict) _hf_g = has_field(German_fields, note_dict) _hf_f = has_field(French_fields, note_dict) if (_hf_m or _hf_e or _hf_g or _hf_f) and has_field( Hanzi_fields, note_dict): d_has_fields += 1 msg_string = "<b>Processing:</b> %(hanzi)s<br><b>Chinese notes:</b> %(has_fields)d<br><b>Translated:</b> %(filled)d<br><b>Failed:</b> %(failed)d" % { "hanzi": cleanup(no_html(get_any(Hanzi_fields, note_dict))), "has_fields": d_has_fields, "filled": d_success, "failed": d_failed } mw.progress.update(label=msg_string, value=d_scanned) hanzi = get_any(Hanzi_fields, note_dict) empty = len(get_any(Meaning_fields, note_dict)) empty += len(get_any(English_fields, note_dict)) empty += len(get_any(German_fields, note_dict)) empty += len(get_any(French_fields, note_dict)) if not (empty): result = 0 if _hf_m: result += update_Meaning_fields(hanzi, note_dict) if _hf_e: result += update_English_fields(hanzi, note_dict) if _hf_g: result += update_German_fields(hanzi, note_dict) if _hf_f: result += update_French_fields(hanzi, note_dict) if result == 0: d_failed += 1 if d_failed < 20: failed_hanzi += [ cleanup(no_html(get_any(Hanzi_fields, note_dict))) ] else: d_success += 1 def write_back(fields): for f in fields: if note_dict.has_key(f) and note_dict[f] <> note[f]: note[f] = note_dict[f] return # write back to note from dict and flush write_back(Meaning_fields) write_back(English_fields) write_back(German_fields) write_back(French_fields) write_back(Mean_Word_fields) write_back(Alternate_fields) note.flush() msg_string = "<b>Translation complete</b> <br><b>Chinese notes:</b> %(has_fields)d<br><b>Translated:</b> %(filled)d<br><b>Failed:</b> %(failed)d" % { "has_fields": d_has_fields, "filled": d_success, "failed": d_failed } if d_failed > 0: msg_string += "\n\n<div>Translation failures may come either from connection issues (if you're using an on-line translation service), or because some words are not it the dictionary (for local dictionaries).</div>" msg_string += "<div>The following notes failed: " + ", ".join( failed_hanzi) + "</div>" mw.progress.finish() showInfo(msg_string)
def afterSave() -> None: ok = self.editor.fieldsAreBlank(self.previousNote) or askUser( tr(TR.ADDING_CLOSE_AND_LOSE_CURRENT_INPUT), defaultno=True) if ok: onOk()
def fill_translation(): if not (askUser( "<div>This will update the <i>Meaning</i> field in the current " "deck, if they exist and are empty.</div>" "<b>Learning tip:</b><div>Automatic dictionary lookup tends to " "produce very long text, often with multiple translations.</div>" "\n\n" "<div>For more effective memorization, it's highly " "recommended to trim them down to just a few words, only one " "meaning, and possibly add some mnemonics.</div>\n\n" "<div>Dictionary lookup is simply meant as a way to save you time " "when typing; please consider editing each definition by hand when" " you're done.</div>\n\n" "<div>Please back-up your Anki deck first!</div>\n\n" "<div><b>Continue?</b></div>")): return False query_str = "deck:current" d_scanned = 0 d_has_fields = 0 d_success = 0 d_failed = 0 failed_hangul = [] notes = Finder(mw.col).findNotes(query_str) mw.progress.start(immediate=True, min=0, max=len(notes)) for noteId in notes: d_scanned += 1 note = mw.col.getNote(noteId) note_dict = dict(note) # edit_function routines require a dict if has_field(config["fields"]["meaning"], note_dict) and has_field( config["fields"]["hangul"], note_dict): d_has_fields += 1 msg_string = ("<b>Processing:</b> {hangul:s}<br>" "<b>Korean notes:</b> {has_fields:d}<br>" "<b>Translated:</b> {filled:d}<br>" "<b>Failed:</b> {failed:d}").format( hangul=cleanup( no_html( get_any(config["fields"]["hangul"], note_dict))), has_fields=d_has_fields, filled=d_success, failed=d_failed, ) mw.progress.update(label=msg_string, value=d_scanned) hangul = get_any(config["fields"]["hangul"], note_dict) empty = len(get_any(config["fields"]["meaning"], note_dict)) if not (empty): result = update_Meaning_fields(hangul, note_dict) if result == 0: d_failed += 1 if d_failed < 20: failed_hangul += [ cleanup( no_html( get_any(config["fields"]["hangul"], note_dict))) ] else: d_success += 1 def write_back(fields): for f in fields: if f in note_dict and note_dict[f] != note[f]: note[f] = note_dict[f] return # write back to note from dict and flush write_back(config["fields"]["meaning"]) note.flush() msg_string = ("<b>Translation complete</b> <br>" "<b>Korean notes:</b> {has_fields:d}<br>" "<b>Translated:</b> {filled:d}<br>" "<b>Failed:</b> {failed:d}").format(has_fields=d_has_fields, filled=d_success, failed=d_failed) if d_failed > 0: msg_string += ("\n\n<div>Translation failures may come either from " "connection issues (if you're using an on-line " "translation service), or because some words are not in" " the dictionary (for local dictionaries).</div>") msg_string += "<div>The following notes failed: {}</div>".format( ", ".join(failed_hangul)) mw.progress.finish() showInfo(msg_string)
def accept(self): """ If user accept the settings (commit the settings) """ # validate directory if not os.path.exists(self.dirPath): showInfo("Directory not found.\n" "The resource you're looking for might have been removed, " "had its name changed, or is temporary unavailable. \n" "Please select another directory.") self.browse_dir() return # validate provenance try: # Test if a string is filename-ok by creating a file with open(self.prov, 'w'): pass os.remove(self.prov) except (FileNotFoundError, OSError): _prov = 'Unknown' if askUser(""" Provenance will be used to rename files, so it cannot be empty or contain any of the following characters:\n /\\:*?"<>|\n If you choose 'Yes', you'll return to edit the provenance.\n If you choose 'No', provenance will be '%s'. """ % _prov): self.form.provInput.setFocus() self.form.provInput.selectAll() return else: self.prov = _prov # validate deck if not self.deckName: self.deckName = mw.col.decks.current()['name'] # validate model if not self.modelName: self.modelName = mw.col.models.current()['name'] # get field map self.fieldMap = {} for row in range(len(mw.col.models.byName(self.modelName)['flds'])): # QLabel with field name field = self.form.fieldMapGrid.itemAtPosition(row, 0).widget().text() # QComboBox with index from the FILLING_OPTIONS list option_idx = self.form.fieldMapGrid.itemAtPosition(row, 1).widget().currentIndex() self.fieldMap[field] = option_idx # logging logging.info("Final dirPath = " + self.dirPath) logging.info("Final prov = " + self.prov) logging.info("Final deckName = " + self.deckName) logging.info("Final modelName = " + self.modelName) logging.info('fieldMap = \n' + json.dumps(self.fieldMap, indent=4)) logging.info("Final tags = " + self.tagsTxt) # save user settings settings_dict = { self.DIR_PATH_KEY: self.dirPath, self.PROV_KEY: self.prov, self.DECK_NAME_KEY: self.deckName, self.MODEL_NAME_KEY: self.modelName, self.FIELD_MAP_KEY: self.fieldMap, self.TAGS_TXT_KEY: self.tagsTxt } with open(self.SETTINGS_JSON_PATH, 'w') as f: f.write(json.dumps(settings_dict, indent=4)) QDialog.accept(self)
def bulk_fill_usage(): prompt = PROMPT_TEMPLATE.format(field_names='<i>usage</i>', extra_info='') progress_msg_template = ''' <b>Processing:</b> %(hanzi)s<br> <b>Chinese notes:</b> %(has_fields)d<br> <b>Cards with Sentences added:</b> %(filled)d<br> <b>Cards with no Sentences added:</b> %(not_filled)d<br> <b>Failed:</b> %(failed)d''' fields = config.get_fields(['usage']) if not askUser(prompt): return n_processed = 0 n_updated = 0 n_failed = 0 n_notfilled = 0 failed_hanzi = [] note_ids = Finder(mw.col).findNotes('deck:current') mw.progress.start(immediate=True, min=0, max=len(note_ids)) for i, note_id in enumerate(note_ids): note = mw.col.getNote(note_id) copy = dict(note) hanzi = get_hanzi(copy) if has_any_field(copy, fields) and hanzi: n_processed += 1 try: if all_fields_empty(copy, fields): result = fill_usage(hanzi, copy) if result: n_updated += 1 else: n_notfilled += 1 except: n_failed += 1 failed_hanzi.append(hanzi) msg = progress_msg_template % { 'hanzi': hanzi, 'has_fields': n_processed, 'filled': n_updated, 'not_filled': n_notfilled, 'failed': n_failed, } mw.progress.update(label=msg, value=i) save_note(note, copy) msg = ''' <b>Usage Additions Complete</b><br> <b>Chinese Notes:</b> %(has_fields)d<br> <b>Usage Fields Filled:</b> %(filled)d<br> <b>Usage Fields Not Filled:</b> %(not_filled)d<br> <b>Failed:</b> %(failed)d''' % { 'has_fields': n_processed, 'filled': n_updated, 'not_filled': n_notfilled, 'failed': n_failed, } if n_failed > 0: failed_msg = ( 'Usages may not be available in the database\'s data set. ' 'Custom data can be added to the english_usage column in the' 'chinese.db database.\n' 'The following notes failed: \n\n' + ', '.join(failed_hanzi)) showText(failed_msg, copyBtn=True) mw.progress.finish() showInfo(msg)
def fill_pinyin(collection, view_key): if view_key == "deckBrowser": return showInfo(u"Please first select one of your decks.") if not (askUser( "<div>This will update the <i>Pinyin</i> (or <i>Transcription</i>), <i>Color</i> and <i>Ruby</i> fields in the current deck, if they exist.</div>\n\n<div><i>Pinyin</i> and <i>Transcription</i> will be filled if empty. Otherwise, their colorization and accentuation will be refreshed as needed.</div>\n\n<div>Please back-up your Anki deck first!</div>\n\n<div><b>Continue?</b></div>" )): return False query_str = "deck:current" d_scanned = 0 d_has_fields = 0 d_failed = 0 d_added_pinyin = 0 d_updated = 0 notes = Finder(collection).findNotes(query_str) mw.progress.start(immediate=True, min=0, max=len(notes)) for noteId in notes: d_scanned += 1 note = collection.getNote(noteId) note_dict = dict(note) # edit_function routines require a dict _hf_t = has_field(Transcription_fields, note_dict) _hf_py = has_field(Pinyin_fields, note_dict) _hf_pytw = has_field(PinyinTW_fields, note_dict) _hf_cant = has_field(Cantonese_fields, note_dict) _hf_bpmf = has_field(Bopomofo_fields, note_dict) if (_hf_t or _hf_py or _hf_pytw or _hf_cant or _hf_bpmf) and has_field( Hanzi_fields, note_dict): d_has_fields += 1 msg_string = "<b>Processing:</b> %(hanzi)s<br><b>Filled pinyin:</b> %(pinyin)d notes<br><b>Updated: </b>%(updated)d fields" % { "hanzi": cleanup(no_html(get_any(Hanzi_fields, note_dict))), "pinyin": d_added_pinyin, "updated": d_updated } mw.progress.update(label=msg_string, value=d_scanned) hanzi = get_any(Hanzi_fields, note_dict) results = 0 if _hf_t: results += update_Transcription_fields(hanzi, note_dict) if _hf_py: results += update_Pinyin_fields(hanzi, note_dict) if _hf_pytw: results += update_PinyinTW_fields(hanzi, note_dict) if _hf_cant: results += update_Cantonese_fields(hanzi, note_dict) if _hf_bpmf: results += update_Bopomofo_fields(hanzi, note_dict) if results != 0: d_added_pinyin += 1 #Always overwrite, as in the default edit_behavior update_all_Color_fields(hanzi, note_dict) #Update ruby field update_all_Ruby_fields(hanzi, note_dict) def write_back(fields): num_updated = 0 for f in fields: if note_dict.has_key(f) and note_dict[f] <> note[f]: note[f] = note_dict[f] num_updated += 1 return num_updated # write back to note from dict and flush d_updated += write_back(Transcription_fields) d_updated += write_back(Pinyin_fields) d_updated += write_back(PinyinTW_fields) d_updated += write_back(Cantonese_fields) d_updated += write_back(Bopomofo_fields) d_updated += write_back(Color_fields) d_updated += write_back(ColorPY_fields) d_updated += write_back(ColorPYTW_fields) d_updated += write_back(ColorCANT_fields) d_updated += write_back(ColorBPMF_fields) d_updated += write_back(Ruby_fields) d_updated += write_back(RubyPY_fields) d_updated += write_back(RubyPYTW_fields) d_updated += write_back(RubyCANT_fields) d_updated += write_back(RubyBPMF_fields) note.flush() mw.progress.finish() msg_string = "<b>Processing:</b> %(hanzi)s<br><b>Filled pinyin:</b> %(pinyin)d notes<br><b>Updated: </b>%(updated)d fields" % { "hanzi": cleanup(no_html(get_any(Hanzi_fields, note_dict))), "pinyin": d_added_pinyin, "updated": d_updated } showInfo(msg_string)
def bulk_fill_sound(): prompt = PROMPT_TEMPLATE.format( field_names='<i>Sound</i>', extra_info=( '<div>There will be a 5 second delay between each sound request,' ' so this may take a while.</div>'), ) fields = config.get_fields(['sound', 'mandarinSound', 'cantoneseSound']) if not askUser(prompt): return d_has_fields = 0 d_already_had_sound = 0 d_success = 0 d_failed = 0 note_ids = Finder(mw.col).findNotes('deck:current') mw.progress.start(immediate=True, min=0, max=len(note_ids)) for i, nid in enumerate(note_ids): orig = mw.col.getNote(nid) copy = dict(orig) if has_any_field(copy, fields) and has_any_field( config['fields']['hanzi'], copy): d_has_fields += 1 hanzi = get_first(config['fields']['hanzi'], copy) if all_fields_empty(copy, fields): msg = ''' <b>Processing:</b> %(hanzi)s<br> <b>Updated:</b> %(d_success)d notes<br> <b>Failed:</b> %(d_failed)d notes''' % { 'hanzi': get_hanzi(copy), 'd_success': d_success, 'd_failed': d_failed, } mw.progress.update(label=msg, value=i) s, f = fill_sound(hanzi, copy) d_success += s d_failed += f save_note(orig, copy) sleep(5) else: d_already_had_sound += 1 mw.progress.finish() msg = ''' %(d_success)d new pronunciations downloaded %(d_failed)d downloads failed %(have)d/%(d_has_fields)d notes now have pronunciation''' % { 'd_success': d_success, 'd_failed': d_failed, 'have': d_already_had_sound + d_success, 'd_has_fields': d_has_fields, } if d_failed > 0: msg += ('TTS is taken from an online source. ' 'It may not always be fully responsive. ' 'Please check your network connection, or retry later.') showInfo(msg)
def fill_sounds(collection, view_key): if view_key == "deckBrowser": return showInfo(u"Please first select one of your decks.") if not (askUser( "<div>This will update the <i>Sound</i> fields in the current deck, if they exist and are empty, using the selected speech engine.</div>\n\n<div>Please back-up your Anki deck first!</div>\n\n<div><b>Continue?</b></div>" )): return False query_str = "deck:current" d_scanned = 0 d_has_fields = 0 d_already_had_sound = 0 d_success = 0 d_failed = 0 notes = Finder(collection).findNotes(query_str) mw.progress.start(immediate=True, min=0, max=len(notes)) for noteId in notes: d_scanned += 1 note = collection.getNote(noteId) note_dict = dict(note) # edit_function routines require a dict _hf_s = has_field(Sound_fields, note_dict) _hf_sm = has_field(Sound_Mandarin_fields, note_dict) _hf_sc = has_field(Sound_Cantonese_fields, note_dict) if (_hf_s or _hf_sm or _hf_sc) and has_field(Hanzi_fields, note_dict): d_has_fields += 1 hanzi = get_any(Hanzi_fields, note_dict) if get_any(Sound_fields, note_dict) or get_any( Sound_Mandarin_fields, note_dict) or get_any( Sound_Cantonese_fields, note_dict): d_already_had_sound += 1 else: msg_string = "<b>Processing:</b> %(hanzi)s<br><b>Updated:</b> %(d_success)d notes<br><b>Failed:</b> %(d_failed)d notes" % { "hanzi": cleanup(no_html(get_any(Hanzi_fields, note_dict))), "d_success": d_success, "d_failed": d_failed } mw.progress.update(label=msg_string, value=d_scanned) s, f = update_all_Sound_fields(hanzi, note_dict) d_success += s d_failed += f # write back to note from dict and flush for f in Sound_fields + Sound_Mandarin_fields + Sound_Cantonese_fields: if note_dict.has_key(f) and note_dict[f] <> note[f]: note[f] = note_dict[f] note.flush() mw.progress.finish() msg_string = ''' %(d_success)d new pronunciations downloaded %(d_failed)d downloads failed %(have)d/%(d_has_fields)d notes now have pronunciation ''' % { "d_success": d_success, "d_failed": d_failed, "have": d_already_had_sound + d_success, "d_has_fields": d_has_fields } if d_failed > 0: msg_string = msg_string + "\n\nTTS is taken from an on-line source. It may not always be fully responsive. Please check your network connexion, or retry later." showInfo(msg_string)
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( QStandardPaths.writableLocation( QStandardPaths.DesktopLocation), "collection.apkg") if not os.path.exists(os.path.dirname(file)): usingHomedir = True file = os.path.join( QStandardPaths.writableLocation( QStandardPaths.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, '{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) as e: showWarning(_("Couldn't save file: %s") % str(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: self.mw.progress.finish() QDialog.accept(self)