def downloadMedia(url, editor): # Local file : just read the file content if url.startswith("file://"): try: url = url[7:] # On windows, paths tend to be prefixed by file:/// # rather than file://, so we remove redundant slash. if re.match(r'^/[A-Za-z]:\\', url): url = url[1:] return open(url, 'rb').read() except OSError: pass app = editor.mw.app # Show download dialog d = QDialog(editor.parentWindow) d.setWindowTitle("Downloading media (0.0%)") d.setWindowModality(Qt.WindowModal) vbox = QVBoxLayout() label = QLabel(url) label.setWordWrap(True) vbox.addWidget(label) d.setLayout(vbox) d.show() # Download chunk by chunk for progress bar try: response = urllib2.urlopen(url) totSize = int(response.info().getheader('Content-Length').strip()) currentRead = 0 chunk_size = 16384 chunks = [] while True: chunk = response.read(chunk_size) currentRead += len(chunk) if not chunk: break d.setWindowTitle("Downloading media (%.1f%%)" % (currentRead * 100.0 / totSize)) app.processEvents() chunks.append(chunk) return ''.join(chunks) except urllib2.URLError: return None finally: d.close() del d
def chooseList(prompt, choices, startrow=0, parent=None): if not parent: parent = aqt.mw.app.activeWindow() d = QDialog(parent) d.setWindowModality(Qt.WindowModal) l = QVBoxLayout() d.setLayout(l) t = QLabel(prompt) l.addWidget(t) c = QListWidget() c.addItems(choices) c.setCurrentRow(startrow) l.addWidget(c) bb = QDialogButtonBox(QDialogButtonBox.Ok) bb.accepted.connect(d.accept) l.addWidget(bb) d.exec_() return c.currentRow()
def get_id_and_pass_from_user(mw: aqt.main.AnkiQt, username="", password="") -> Tuple[str, str]: diag = QDialog(mw) diag.setWindowTitle("Anki") diag.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # type: ignore diag.setWindowModality(Qt.WindowModal) vbox = QVBoxLayout() info_label = QLabel( without_unicode_isolation( tr(TR.SYNC_ACCOUNT_REQUIRED, link="https://ankiweb.net/account/register"))) info_label.setOpenExternalLinks(True) info_label.setWordWrap(True) vbox.addWidget(info_label) vbox.addSpacing(20) g = QGridLayout() l1 = QLabel(tr(TR.SYNC_ANKIWEB_ID_LABEL)) g.addWidget(l1, 0, 0) user = QLineEdit() user.setText(username) g.addWidget(user, 0, 1) l2 = QLabel(tr(TR.SYNC_PASSWORD_LABEL)) g.addWidget(l2, 1, 0) passwd = QLineEdit() passwd.setText(password) passwd.setEchoMode(QLineEdit.Password) g.addWidget(passwd, 1, 1) vbox.addLayout(g) bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) # type: ignore bb.button(QDialogButtonBox.Ok).setAutoDefault(True) qconnect(bb.accepted, diag.accept) qconnect(bb.rejected, diag.reject) vbox.addWidget(bb) diag.setLayout(vbox) diag.show() accepted = diag.exec_() if not accepted: return ("", "") return (user.text().strip(), passwd.text())
def get_id_and_pass_from_user(mw: aqt.main.AnkiQt, username: str = "", password: str = "") -> tuple[str, str]: diag = QDialog(mw) diag.setWindowTitle("Anki") disable_help_button(diag) diag.setWindowModality(Qt.WindowModality.WindowModal) vbox = QVBoxLayout() info_label = QLabel( without_unicode_isolation( tr.sync_account_required( link="https://ankiweb.net/account/register"))) info_label.setOpenExternalLinks(True) info_label.setWordWrap(True) vbox.addWidget(info_label) vbox.addSpacing(20) g = QGridLayout() l1 = QLabel(tr.sync_ankiweb_id_label()) g.addWidget(l1, 0, 0) user = QLineEdit() user.setText(username) g.addWidget(user, 0, 1) l2 = QLabel(tr.sync_password_label()) g.addWidget(l2, 1, 0) passwd = QLineEdit() passwd.setText(password) passwd.setEchoMode(QLineEdit.EchoMode.Password) g.addWidget(passwd, 1, 1) vbox.addLayout(g) bb = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) # type: ignore bb.button(QDialogButtonBox.StandardButton.Ok).setAutoDefault(True) qconnect(bb.accepted, diag.accept) qconnect(bb.rejected, diag.reject) vbox.addWidget(bb) diag.setLayout(vbox) diag.show() accepted = diag.exec() if not accepted: return ("", "") return (user.text().strip(), passwd.text())
def _getUserPass(self): d = QDialog(self.mw) d.setWindowTitle("Anki") d.setWindowModality(Qt.WindowModal) vbox = QVBoxLayout() l = QLabel( _("""\ <h1>Account Required</h1> A free account is required to keep your collection synchronized. Please \ <a href="%s">sign up</a> for an account, then \ enter your details below.""") % "https://ankiweb.net/account/login") l.setOpenExternalLinks(True) l.setWordWrap(True) vbox.addWidget(l) vbox.addSpacing(20) g = QGridLayout() l1 = QLabel(_("AnkiWeb ID:")) g.addWidget(l1, 0, 0) user = QLineEdit() g.addWidget(user, 0, 1) l2 = QLabel(_("Password:")) g.addWidget(l2, 1, 0) passwd = QLineEdit() passwd.setEchoMode(QLineEdit.Password) g.addWidget(passwd, 1, 1) vbox.addLayout(g) bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bb.button(QDialogButtonBox.Ok).setAutoDefault(True) bb.accepted.connect(d.accept) bb.rejected.connect(d.reject) vbox.addWidget(bb) d.setLayout(vbox) d.show() accepted = d.exec_() u = user.text() p = passwd.text() if not accepted or not u or not p: return return (u, p)
class Replacer: find: str replace: str tags: str case: int combo = "FindAndReplaceTags" find_history: List replace_history: List n_tags_changed = 0 n_notes_changed = 0 n_replacements = 0 def __init__(self, browser): self.b = browser if not self.b.selectedNotes(): tooltip("No cards selected.") return self.d = QDialog(self.b) self.f = Ui_Dialog() self.set_up_form() self.d.setWindowModality(Qt.WindowModal) r = self.d.exec_() if not r: return self.save_history() self.b.mw.checkpoint(_("Find and Replace Tags")) self.b.model.beginReset() self.b.mw.taskman.run_in_background(self.do_find_replace, self.on_done) def set_up_form(self): self.f.setupUi(self.d) self.connect_signals() self.restore_history() self.f.input_tags.setCol(self.b.col) self.on_input_changed() def connect_signals(self): self.f.input_find.currentTextChanged.connect(self.on_input_changed) self.f.input_replace.currentTextChanged.connect(self.on_input_changed) self.f.is_case.stateChanged.connect(self.on_input_changed) self.f.input_tags.textChanged.connect(self.on_input_changed) self.f.buttonBox.button(QDialogButtonBox.Help).pressed.connect(on_help) def restore_history(self): self.find_history = restore_combo_history(self.f.input_find, self.combo + "Find") self.f.input_find.completer().setCaseSensitivity(True) self.replace_history = restore_combo_history(self.f.input_replace, self.combo + "Replace") self.f.input_replace.completer().setCaseSensitivity(True) def save_history(self): save_combo_history(self.f.input_find, self.find_history, self.combo + "Find") save_combo_history(self.f.input_replace, self.replace_history, self.combo + "Replace") def on_input_changed(self): self.read_input() enable = False try: re.sub(self.find, self.replace, "") except re.error: out = "INVALID EXPRESSION" else: out = self.tag_preview() if self.find or self.replace: enable = True self.toggle_okay(enable) self.f.output_tags.setText(out) def read_input(self): self.find = self.f.input_find.currentText() self.replace = self.f.input_replace.currentText() self.case = 0 if self.f.is_case.isChecked() else re.I self.tags = self.f.input_tags.text().split() def tag_preview(self): pattern = re.compile(self.find, flags=self.case) new_tags = [pattern.sub(self.replace, t) for t in self.tags] return " ".join(set(new_tags)) def toggle_okay(self, enabled): self.f.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled) def do_find_replace(self): nids = self.b.selectedNotes() pattern = re.compile(self.find, flags=self.case) for nid in nids: note = self.b.col.getNote(nid) tags_subs = [pattern.subn(self.replace, tag) for tag in note.tags] new_tags = [t[0] for t in tags_subs] note.tags = new_tags note.flush() replacements = [t[1] for t in tags_subs if t[1] != 0] self.n_replacements += sum(replacements) n_tags_changed = len(replacements) self.n_tags_changed += n_tags_changed self.n_notes_changed += (n_tags_changed > 0) def on_done(self, _): self.b.search() self.b.mw.requireReset() self.b.model.endReset() self.b.mw.reset() t1 = " was" if self.n_replacements == 1 else "s were" t2 = "" if self.n_tags_changed == 1 else "s" t3 = "" if self.n_notes_changed == 1 else "s" msg = f"{self.n_replacements} replacement{t1} made " \ f"in {self.n_tags_changed} tag{t2} " \ f"of {self.n_notes_changed} note{t3}." \ f"<br>Do you wish to clear unused tags now?" if askUser(msg, parent=self.b): self.b.clearUnusedTags()