示例#1
0
文件: clayout.py 项目: solarmist/anki
    def onTargetDeck(self):
        from aqt.tagedit import TagEdit
        t = self.card.template()
        d = QDialog(self)
        d.setWindowTitle("Anki")
        d.setMinimumWidth(400)
        l = QVBoxLayout()
        lab = QLabel(_("""\
Enter deck to place new %s cards in, or leave blank:""") %
                           self.card.template()['name'])
        lab.setWordWrap(True)
        l.addWidget(lab)
        te = TagEdit(d, type=1)
        te.setCol(self.col)
        l.addWidget(te)
        if t['did']:
            te.setText(self.col.decks.get(t['did'])['name'])
            te.selectAll()
        bb = QDialogButtonBox(QDialogButtonBox.Close)
        bb.rejected.connect(d.close)
        l.addWidget(bb)
        d.setLayout(l)
        d.exec_()
        if not te.text().strip():
            t['did'] = None
        else:
            t['did'] = self.col.decks.id(te.text())
示例#2
0
文件: clayout.py 项目: solarmist/anki
 def onBrowserDisplay(self):
     d = QDialog()
     f = aqt.forms.browserdisp.Ui_Dialog()
     f.setupUi(d)
     t = self.card.template()
     f.qfmt.setText(t.get('bqfmt', ""))
     f.afmt.setText(t.get('bafmt', ""))
     if t.get("bfont"):
         f.overrideFont.setChecked(True)
     f.font.setCurrentFont(QFont(t.get('bfont', "Arial")))
     f.fontSize.setValue(t.get('bsize', 12))
     f.buttonBox.accepted.connect(lambda: self.onBrowserDisplayOk(f))
     d.exec_()
示例#3
0
文件: clayout.py 项目: solarmist/anki
 def onAddField(self):
     diag = QDialog(self)
     form = aqt.forms.addfield.Ui_Dialog()
     form.setupUi(diag)
     fields = [f['name'] for f in self.model['flds']]
     form.fields.addItems(fields)
     form.font.setCurrentFont(QFont("Arial"))
     form.size.setValue(20)
     diag.show()
     # Work around a Qt bug,
     # https://bugreports.qt-project.org/browse/QTBUG-1894
     if isMac or isWin:
         # No problems on Macs or Windows.
         form.fields.showPopup()
     else:
         # Delay showing the pop-up.
         self.mw.progress.timer(200, form.fields.showPopup, False)
     if not diag.exec_():
         return
     if form.radioQ.isChecked():
         obj = self.tform.front
     else:
         obj = self.tform.back
     self._addField(obj,
                    fields[form.fields.currentIndex()],
                    form.font.currentFont().family(),
                    form.size.value())
示例#4
0
    def onCheckMediaDB(self):
        self.progress.start(immediate=True)
        (nohave, unused, warnings) = self.col.media.check()
        self.progress.finish()
        # generate report
        report = ""
        if warnings:
            report += "\n".join(warnings) + "\n"
        if unused:
            if report:
                report += "\n\n\n"
            report += _(
                "In media folder but not used by any cards:")
            report += "\n" + "\n".join(unused)
        if nohave:
            if report:
                report += "\n\n\n"
            report += _(
                "Used on cards but missing from media folder:")
            report += "\n" + "\n".join(nohave)
        if not report:
            tooltip(_("No unused or missing files found."))
            return
        # show report and offer to delete
        diag = QDialog(self)
        diag.setWindowTitle("Anki")
        layout = QVBoxLayout(diag)
        diag.setLayout(layout)
        text = QTextEdit()
        text.setReadOnly(True)
        text.setPlainText(report)
        layout.addWidget(text)
        box = QDialogButtonBox(QDialogButtonBox.Close)
        layout.addWidget(box)
        if unused:
            b = QPushButton(_("Delete Unused Files"))
            b.setAutoDefault(False)
            box.addButton(b, QDialogButtonBox.ActionRole)
            b.clicked.connect(
                lambda c, u=unused, d=diag: self.deleteUnused(u, d))

        box.rejected.connect(diag.reject)
        diag.setMinimumHeight(400)
        diag.setMinimumWidth(500)
        restoreGeom(diag, "checkmediadb")
        diag.exec_()
        saveGeom(diag, "checkmediadb")
示例#5
0
文件: editor.py 项目: solarmist/anki
 def _onHtmlEdit(self, field):
     d = QDialog(self.widget)
     form = aqt.forms.edithtml.Ui_Dialog()
     form.setupUi(d)
     form.buttonBox.helpRequested.connect(lambda: openHelp("editor"))
     form.textEdit.setPlainText(self.note.fields[field])
     form.textEdit.moveCursor(QTextCursor.End)
     d.exec_()
     html = form.textEdit.toPlainText()
     # filter html through beautifulsoup so we can strip out things like a
     # leading </div>
     with warnings.catch_warnings() as w:
         warnings.simplefilter('ignore', UserWarning)
         html = str(BeautifulSoup(html, "html.parser"))
     self.note.fields[field] = html
     self.note.flush()
     self.loadNote(focusTo=field)
示例#6
0
文件: utils.py 项目: solarmist/anki
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()
示例#7
0
文件: utils.py 项目: solarmist/anki
def showText(txt, parent=None, type="text", run=True, geomKey=None, \
        minWidth=500, minHeight=400, title="Anki", copyBtn=False):
    if not parent:
        parent = aqt.mw.app.activeWindow() or aqt.mw
    diag = QDialog(parent)
    diag.setWindowTitle(title)
    layout = QVBoxLayout(diag)
    diag.setLayout(layout)
    text = QTextBrowser()
    text.setOpenExternalLinks(True)
    if type == "text":
        text.setPlainText(txt)
    else:
        text.setHtml(txt)
    layout.addWidget(text)
    box = QDialogButtonBox(QDialogButtonBox.Close)
    layout.addWidget(box)
    if copyBtn:
        def onCopy():
            QApplication.clipboard().setText(text.toPlainText())
        btn = QPushButton(_("Copy to Clipboard"))
        btn.clicked.connect(onCopy)
        box.addButton(btn, QDialogButtonBox.ActionRole)
    def onReject():
        if geomKey:
            saveGeom(diag, geomKey)
        QDialog.reject(diag)
    box.rejected.connect(onReject)
    def onFinish():
        if geomKey:
            saveGeom(diag, geomKey)
    box.accepted.connect(onFinish)
    diag.setMinimumHeight(minHeight)
    diag.setMinimumWidth(minWidth)
    if geomKey:
        restoreGeom(diag, geomKey)
    if run:
        diag.exec_()
    else:
        return diag, box
示例#8
0
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())
示例#9
0
文件: sync.py 项目: v-limc/anki
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.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.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())
示例#10
0
    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)
示例#11
0
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()
示例#12
0
    def setup(self):
        addonconfig = mw.addonManager.getConfig(__name__)
        config = types.SimpleNamespace(**addonconfig['defaults'])
        if addonconfig.get("_debug_time", False):
            self.timepoint = lambda c: print("%s: %0.3f" %
                                             (c, time.time() - self.time))
        else:
            self.timepoint = lambda _: None
        config.did = mw.col.conf['curDeck']

        swin = QDialog(mw)
        vl = QVBoxLayout()
        fl = QHBoxLayout()
        deckcb = QComboBox()
        deckcb.addItems(sorted(mw.col.decks.allNames()))
        deckcb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        fl.addWidget(QLabel("Deck: "))
        deckcb.setCurrentText(mw.col.decks.get(config.did)['name'])

        def change_did(deckname):
            config.did = mw.col.decks.byName(deckname)['id']

        deckcb.currentTextChanged.connect(change_did)
        fl.addWidget(deckcb)
        vl.addLayout(fl)
        frm = QGroupBox("Settings")
        vl.addWidget(frm)
        il = QVBoxLayout()
        fl = QHBoxLayout()
        field = QLineEdit()
        field.setPlaceholderText(
            "e.g. \"kanji\", \"hanzi\" or \"sentence-kanji\" (default: \"%s\")"
            % config.pattern)
        il.addWidget(
            QLabel("Pattern or Field names to search for (case insensitive):"))
        fl.addWidget(field)
        liter = QCheckBox("Match exactly")
        liter.setChecked(config.literal)
        fl.addWidget(liter)
        il.addLayout(fl)
        stint = QSpinBox()
        stint.setRange(1, 65536)
        stint.setValue(config.interval)
        il.addWidget(QLabel("Card interval considered strong:"))
        il.addWidget(stint)
        ttcol = QSpinBox()
        ttcol.setRange(1, 99)
        ttcol.setValue(config.thin)
        il.addWidget(QLabel("Number of Columns in the in-app table:"))
        il.addWidget(ttcol)
        wtcol = QSpinBox()
        wtcol.setRange(1, 99)
        wtcol.setValue(config.wide)
        il.addWidget(QLabel("Number of Columns in the exported table:"))
        il.addWidget(wtcol)
        groupby = QComboBox()
        groupby.addItems([
            *("None, sorted by " + x.pretty_value() for x in SortOrder),
            *(x.name for x in data.groups),
        ])
        groupby.setCurrentIndex(config.groupby)
        il.addWidget(QLabel("Group by:"))
        il.addWidget(groupby)
        shnew = QCheckBox("Show units not yet seen")
        shnew.setChecked(config.unseen)
        il.addWidget(shnew)
        toolt = QCheckBox("Show informational tooltips")
        toolt.setChecked(config.tooltips)
        il.addWidget(toolt)
        frm.setLayout(il)
        hl = QHBoxLayout()
        vl.addLayout(hl)
        gen = QPushButton("Generate", clicked=swin.accept)
        hl.addWidget(gen)
        cls = QPushButton("Close", clicked=swin.reject)
        hl.addWidget(cls)
        swin.setLayout(vl)
        swin.setTabOrder(gen, cls)
        swin.setTabOrder(cls, field)
        swin.setTabOrder(field, liter)
        swin.setTabOrder(liter, stint)
        swin.setTabOrder(stint, ttcol)
        swin.setTabOrder(ttcol, wtcol)
        swin.setTabOrder(wtcol, groupby)
        swin.setTabOrder(groupby, shnew)
        swin.setTabOrder(shnew, toolt)
        swin.resize(500, 400)
        if swin.exec_():
            mw.progress.start(immediate=True)
            if len(field.text().strip()) != 0:
                config.pattern = field.text().lower()
            config.pattern = config.pattern.split()
            config.literal = liter.isChecked()
            config.interval = stint.value()
            config.thin = ttcol.value()
            config.wide = wtcol.value()
            config.groupby = groupby.currentIndex()
            config.unseen = shnew.isChecked()
            config.tooltips = toolt.isChecked()
            self.makegrid(config)
            mw.progress.finish()
            self.win.show()
示例#13
0
    def setup(self):
        addonconfig = mw.addonManager.getConfig(__name__)
        config = types.SimpleNamespace(**addonconfig['defaults'])
        if addonconfig.get("_debug_time", False):
            self.timepoint = lambda c: print("%s: %0.3f" % (c, time.time()-self.time))
        else:
            self.timepoint = lambda _: None
        config.did = mw.col.conf['curDeck']

        swin = QDialog(mw)
        vl = QVBoxLayout()
        fl = QHBoxLayout()
        deckcb = QComboBox()
        deckcb.addItems(sorted(mw.col.decks.allNames()))
        deckcb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        fl.addWidget(QLabel("Deck: "))
        deckcb.setCurrentText(mw.col.decks.get(config.did)['name'])
        def change_did(deckname):
            config.did = mw.col.decks.byName(deckname)['id']
        deckcb.currentTextChanged.connect(change_did)
        fl.addWidget(deckcb)
        vl.addLayout(fl)
        frm = QGroupBox("Settings")
        vl.addWidget(frm)
        il = QVBoxLayout()
        fl = QHBoxLayout()
        field = QLineEdit()
        field.setPlaceholderText("e.g. \"kanji\" or \"sentence-kanji\" (default: \"%s\")" % config.pattern)
        il.addWidget(QLabel("Pattern or Field names to search for (case insensitive):"))
        fl.addWidget(field)
        liter = QCheckBox("Match exactly")
        liter.setChecked(config.literal)
        fl.addWidget(liter)
        il.addLayout(fl)
        stint = QSpinBox()
        stint.setRange(1, 65536)
        stint.setValue(config.interval)
        il.addWidget(QLabel("Card interval considered strong:"))
        il.addWidget(stint)
        ttcol = QSpinBox()
        ttcol.setRange(1, 99)
        ttcol.setValue(config.thin)
        il.addWidget(QLabel("Number of Columns:"))
        coll = QHBoxLayout()
        coll.addWidget(QLabel("In-app:"))
        coll.addWidget(ttcol)
        wtcol = QSpinBox()
        wtcol.setRange(1, 99)
        wtcol.setValue(config.wide)
        coll.addWidget(QLabel("Exported:"))
        coll.addWidget(wtcol)
        itcol = QCheckBox("Don't care")
        itcol.setChecked(addonconfig['defaults'].get("autothinwide", False))
        def disableEnableColumnSettings(state):
            ttcol.setEnabled(state != Qt.Checked)
            wtcol.setEnabled(state != Qt.Checked)
        itcol.stateChanged.connect(disableEnableColumnSettings)
        disableEnableColumnSettings(itcol.checkState())
        coll.addWidget(itcol)
        il.addLayout(coll)
        groupby = QComboBox()
        groupby.addItems([
            *("None, sorted by " + x.pretty_value() for x in SortOrder),
            *(x.name for x in data.groups),
        ])
        groupby.setCurrentIndex(config.groupby)
        il.addWidget(QLabel("Group by:"))
        il.addWidget(groupby)
        shnew = QCheckBox("Show units not yet seen")
        shnew.setChecked(config.unseen)
        il.addWidget(shnew)
        toolt = QCheckBox("Show informational tooltips")
        toolt.setChecked(config.tooltips)
        il.addWidget(toolt)
        frm.setLayout(il)
        hl = QHBoxLayout()
        vl.addLayout(hl)
        gen = QPushButton("Generate", clicked=swin.accept)
        hl.addWidget(gen)
        cls = QPushButton("Close", clicked=swin.reject)
        hl.addWidget(cls)
        swin.setLayout(vl)
        swin.setTabOrder(gen, cls)
        swin.setTabOrder(cls, field)
        swin.setTabOrder(field, liter)
        swin.setTabOrder(liter, stint)
        swin.setTabOrder(stint, ttcol)
        swin.setTabOrder(ttcol, wtcol)
        swin.setTabOrder(wtcol, groupby)
        swin.setTabOrder(groupby, shnew)
        swin.setTabOrder(shnew, toolt)
        swin.resize(500, 400)
        if swin.exec_():
            mw.progress.start(immediate=True)
            if len(field.text().strip()) != 0:
                config.pattern = field.text().lower()
            config.pattern = config.pattern.split()
            config.literal = liter.isChecked()
            config.interval = stint.value()
            config.thin = ttcol.value()
            config.wide = wtcol.value()
            config.groupby = groupby.currentIndex()
            config.unseen = shnew.isChecked()
            config.tooltips = toolt.isChecked()
            config.autothinwide = itcol.isChecked()
            self.makegrid(config)
            mw.progress.finish()
            self.win.show()