Exemplo n.º 1
0
    def _create_gui(self):
        self.setWindowTitle(_("Preview"))

        qconnect(self.finished, self._on_finished)
        self.silentlyClose = True
        self.vbox = QVBoxLayout()
        self.vbox.setContentsMargins(0, 0, 0, 0)
        self._web = AnkiWebView(title="previewer")
        self.vbox.addWidget(self._web)
        self.bbox = QDialogButtonBox()

        self._replay = self.bbox.addButton(_("Replay Audio"),
                                           QDialogButtonBox.ActionRole)
        self._replay.setAutoDefault(False)
        self._replay.setShortcut(QKeySequence("R"))
        self._replay.setToolTip(_("Shortcut key: %s" % "R"))
        qconnect(self._replay.clicked, self._on_replay_audio)

        both_sides_button = QCheckBox(_("Show Both Sides"))
        both_sides_button.setShortcut(QKeySequence("B"))
        both_sides_button.setToolTip(_("Shortcut key: %s" % "B"))
        self.bbox.addButton(both_sides_button, QDialogButtonBox.ActionRole)
        self._show_both_sides = self.mw.col.conf.get("previewBothSides", False)
        both_sides_button.setChecked(self._show_both_sides)
        qconnect(both_sides_button.toggled, self._on_show_both_sides)

        self.vbox.addWidget(self.bbox)
        self.setLayout(self.vbox)
        restoreGeom(self, "preview")
Exemplo n.º 2
0
def highlight_terms(webview: AnkiWebView, terms: List[str]):
    # FIXME: anki21 does not seem to support highlighting more than one
    # term at once. Likely a Qt bug / regression.
    # TODO: Perhaps choose to highlight the longest term on anki21.
    # TODO: Find a way to exclude UI text in editor pane from highlighting
    for term in terms:
        webview.findText(term)
Exemplo n.º 3
0
def add_graphs_to_congrats(webview: AnkiWebView):
    page = basename(webview.page().url().path())

    if page != "congrats.html":
        return

    graph_css = make_graph_css()
    graph_js = make_graph_js(get_active_congrats_graphs(), "deck:current")

    webview.eval(f"""
const graphsContainer = document.createElement("div")
graphsContainer.id = "graphsSection"
graphsContainer.style = "text-align: center;"
document.body.appendChild(graphsContainer)

const loadGraphs = () => {{
    {graph_css}
    {graph_js}
}}

const loadGraphScript = () => {{
    const graphScript = document.createElement("script")
    graphScript.onload = loadGraphs
    graphScript.charset = "UTF-8"
    graphScript.src = "graphs.js"
    document.head.appendChild(graphScript)
}}

const protobufScript = document.createElement("script")
protobufScript.onload = loadGraphScript
protobufScript.charset = "UTF-8"
protobufScript.src = "../js/vendor/protobuf.min.js"
document.head.appendChild(protobufScript)
""")
Exemplo n.º 4
0
    def setupUi(self, About):
        About.setObjectName("About")
        About.resize(410, 664)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                           QtWidgets.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(About.sizePolicy().hasHeightForWidth())
        About.setSizePolicy(sizePolicy)
        self.vboxlayout = QtWidgets.QVBoxLayout(About)
        self.vboxlayout.setContentsMargins(0, 0, 0, 0)
        self.vboxlayout.setObjectName("vboxlayout")
        self.label = AnkiWebView(About)
        self.label.setProperty("url", QtCore.QUrl("about:blank"))
        self.label.setObjectName("label")
        self.vboxlayout.addWidget(self.label)
        self.buttonBox = QtWidgets.QDialogButtonBox(About)
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.vboxlayout.addWidget(self.buttonBox)

        self.retranslateUi(About)
        self.buttonBox.accepted.connect(About.accept)
        self.buttonBox.rejected.connect(About.reject)
        QtCore.QMetaObject.connectSlotsByName(About)
Exemplo n.º 5
0
    def setup_preview(self) -> None:
        pform = self.pform
        self.preview_web = AnkiWebView(title="card layout")
        pform.verticalLayout.addWidget(self.preview_web)
        pform.verticalLayout.setStretch(1, 99)
        pform.preview_front.isChecked()
        qconnect(pform.preview_front.clicked, self.on_preview_toggled)
        qconnect(pform.preview_back.clicked, self.on_preview_toggled)
        pform.preview_settings.setText(
            f"{tr.card_templates_preview_settings()} {downArrow()}")
        qconnect(pform.preview_settings.clicked, self.on_preview_settings)

        self.preview_web.stdHtml(
            self.mw.reviewer.revHtml(),
            css=["css/reviewer.css"],
            js=[
                "js/mathjax.js",
                "js/vendor/mathjax/tex-chtml.js",
                "js/reviewer.js",
            ],
            context=self,
        )
        self.preview_web.set_bridge_command(self._on_bridge_cmd, self)

        if self._isCloze():
            nums = list(self.note.cloze_numbers_in_fields())
            if self.ord + 1 not in nums:
                # current card is empty
                nums.append(self.ord + 1)
            self.cloze_numbers = sorted(nums)
            self.setup_cloze_number_box()
        else:
            self.cloze_numbers = []
            self.pform.cloze_number_combo.setHidden(True)
Exemplo n.º 6
0
    def _showQuestion(self) -> None:
        self._reps += 1
        self.state = "question"
        self.typedAnswer: str = None
        c = self.card
        # grab the question and play audio
        q = c.q()
        # play audio?
        if c.autoplay():
            AnkiWebView.setPlaybackRequiresGesture(False)
            sounds = c.question_av_tags()
            gui_hooks.reviewer_will_play_question_sounds(c, sounds)
            av_player.play_tags(sounds)
        else:
            AnkiWebView.setPlaybackRequiresGesture(True)
            av_player.clear_queue_and_maybe_interrupt()
            sounds = []
            gui_hooks.reviewer_will_play_question_sounds(c, sounds)
            av_player.play_tags(sounds)
        # render & update bottom
        q = self._mungeQA(q)
        q = gui_hooks.card_will_show(q, c, "reviewQuestion")

        bodyclass = theme_manager.body_classes_for_card_ord(c.ord)

        self.web.eval(f"_showQuestion({json.dumps(q)},'{bodyclass}');")
        self._drawFlag()
        self._drawMark()
        self._showAnswerButton()
        self.mw.web.setFocus()
        # user hook
        gui_hooks.reviewer_did_show_question(c)
Exemplo n.º 7
0
 def focusInEvent(self, evt):
     AnkiWebView.focusInEvent(self, evt)
     if evt.reason() == Qt.TabFocusReason:
         self.eval("focusField(0);")
     elif evt.reason() == Qt.BacktabFocusReason:
         n = len(self.editor.note.fields) - 1
         self.eval("focusField(%d);" % n)
Exemplo n.º 8
0
    def _create_gui(self):
        self.setWindowTitle(tr(TR.ACTIONS_PREVIEW))

        qconnect(self.finished, self._on_finished)
        self.silentlyClose = True
        self.vbox = QVBoxLayout()
        self.vbox.setContentsMargins(0, 0, 0, 0)
        self._web = AnkiWebView(title="previewer")
        self.vbox.addWidget(self._web)
        self.bbox = QDialogButtonBox()

        self._replay = self.bbox.addButton(tr(TR.ACTIONS_REPLAY_AUDIO),
                                           QDialogButtonBox.ActionRole)
        self._replay.setAutoDefault(False)
        self._replay.setShortcut(QKeySequence("R"))
        self._replay.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="R"))
        qconnect(self._replay.clicked, self._on_replay_audio)

        both_sides_button = QCheckBox(tr(TR.QT_MISC_BACK_SIDE_ONLY))
        both_sides_button.setShortcut(QKeySequence("B"))
        both_sides_button.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="B"))
        self.bbox.addButton(both_sides_button, QDialogButtonBox.ActionRole)
        self._show_both_sides = self.mw.col.conf.get("previewBothSides", False)
        both_sides_button.setChecked(self._show_both_sides)
        qconnect(both_sides_button.toggled, self._on_show_both_sides)

        self.vbox.addWidget(self.bbox)
        self.setLayout(self.vbox)
        restoreGeom(self, "preview")
Exemplo n.º 9
0
 def setupWebviews(self):
     pform = self.pform
     pform.frontWeb = AnkiWebView(title="card layout front")
     pform.frontPrevBox.addWidget(pform.frontWeb)
     pform.backWeb = AnkiWebView(title="card layout back")
     pform.backPrevBox.addWidget(pform.backWeb)
     jsinc = [
         "jquery.js",
         "browsersel.js",
         "mathjax/conf.js",
         "mathjax/MathJax.js",
         "reviewer.js",
     ]
     pform.frontWeb.stdHtml(
         self.mw.reviewer.revHtml(),
         css=["reviewer.css"],
         js=jsinc,
         context=self,
     )
     pform.backWeb.stdHtml(
         self.mw.reviewer.revHtml(),
         css=["reviewer.css"],
         js=jsinc,
         context=self,
     )
     pform.frontWeb.set_bridge_command(self._on_bridge_cmd, self)
     pform.backWeb.set_bridge_command(self._on_bridge_cmd, self)
Exemplo n.º 10
0
    def setup_preview(self):
        pform = self.pform
        self.preview_web = AnkiWebView(title="card layout")
        pform.verticalLayout.addWidget(self.preview_web)
        pform.verticalLayout.setStretch(1, 99)
        pform.preview_front.isChecked()
        qconnect(pform.preview_front.clicked, self.on_preview_toggled)
        qconnect(pform.preview_back.clicked, self.on_preview_toggled)
        pform.preview_settings.setText(
            tr(TR.CARD_TEMPLATES_PREVIEW_SETTINGS) + " " + downArrow()
        )
        qconnect(pform.preview_settings.clicked, self.on_preview_settings)

        jsinc = [
            "jquery.js",
            "browsersel.js",
            "mathjax/conf.js",
            "mathjax/MathJax.js",
            "reviewer.js",
        ]
        self.preview_web.stdHtml(
            self.mw.reviewer.revHtml(), css=["reviewer.css"], js=jsinc, context=self,
        )
        self.preview_web.set_bridge_command(self._on_bridge_cmd, self)

        if self._isCloze():
            nums = list(self.note.cloze_numbers_in_fields())
            if self.ord + 1 not in nums:
                # current card is empty
                nums.append(self.ord + 1)
            self.cloze_numbers = sorted(nums)
            self.setup_cloze_number_box()
        else:
            self.cloze_numbers = []
            self.pform.cloze_number_combo.setHidden(True)
Exemplo n.º 11
0
    def _create_gui(self) -> None:
        self.setWindowTitle(tr.actions_preview())

        self.close_shortcut = QShortcut(QKeySequence("Ctrl+Shift+P"), self)
        qconnect(self.close_shortcut.activated, self.close)

        qconnect(self.finished, self._on_finished)
        self.silentlyClose = True
        self.vbox = QVBoxLayout()
        self.vbox.setContentsMargins(0, 0, 0, 0)
        self._web = AnkiWebView(title="previewer")
        self.vbox.addWidget(self._web)
        self.bbox = QDialogButtonBox()

        self._replay = self.bbox.addButton(
            tr.actions_replay_audio(), QDialogButtonBox.ButtonRole.ActionRole)
        self._replay.setAutoDefault(False)
        self._replay.setShortcut(QKeySequence("R"))
        self._replay.setToolTip(tr.actions_shortcut_key(val="R"))
        qconnect(self._replay.clicked, self._on_replay_audio)

        both_sides_button = QCheckBox(tr.qt_misc_back_side_only())
        both_sides_button.setShortcut(QKeySequence("B"))
        both_sides_button.setToolTip(tr.actions_shortcut_key(val="B"))
        self.bbox.addButton(both_sides_button,
                            QDialogButtonBox.ButtonRole.ActionRole)
        self._show_both_sides = self.mw.col.get_config_bool(
            Config.Bool.PREVIEW_BOTH_SIDES)
        both_sides_button.setChecked(self._show_both_sides)
        qconnect(both_sides_button.toggled, self._on_show_both_sides)

        self.vbox.addWidget(self.bbox)
        self.setLayout(self.vbox)
        restoreGeom(self, "preview")
Exemplo n.º 12
0
    def _render_scheduled(self) -> None:
        self.cancel_timer()
        self._last_render = time.time()

        if not self._open:
            return
        c = self.card()
        func = "_showQuestion"
        if not c:
            txt = tr(TR.QT_MISC_PLEASE_SELECT_1_CARD)
            bodyclass = ""
            self._last_state = None
        else:
            if self._show_both_sides:
                self._state = "answer"
            elif self._card_changed:
                self._state = "question"

            currentState = self._state_and_mod()
            if currentState == self._last_state:
                # nothing has changed, avoid refreshing
                return

            # need to force reload even if answer
            txt = c.q(reload=True)

            if self._state == "answer":
                func = "_showAnswer"
                txt = c.a()
            txt = re.sub(r"\[\[type:[^]]+\]\]", "", txt)

            bodyclass = theme_manager.body_classes_for_card_ord(c.ord)

            if c.autoplay():
                AnkiWebView.setPlaybackRequiresGesture(False)
                if self._show_both_sides:
                    # if we're showing both sides at once, remove any audio
                    # from the answer that's appeared on the question already
                    question_audio = c.question_av_tags()
                    only_on_answer_audio = [
                        x for x in c.answer_av_tags()
                        if x not in question_audio
                    ]
                    audio = question_audio + only_on_answer_audio
                elif self._state == "question":
                    audio = c.question_av_tags()
                else:
                    audio = c.answer_av_tags()
                av_player.play_tags(audio)
            else:
                AnkiWebView.setPlaybackRequiresGesture(True)
                av_player.clear_queue_and_maybe_interrupt()

            txt = self.mw.prepare_card_text_for_display(txt)
            txt = gui_hooks.card_will_show(
                txt, c, "preview" + self._state.capitalize())
            self._last_state = self._state_and_mod()
        self._web.eval("{}({},'{}');".format(func, json.dumps(txt), bodyclass))
        self._card_changed = False
Exemplo n.º 13
0
class CardInfoDialog(QDialog):
    TITLE = "browser card info"
    GEOMETRY_KEY = "revlog"
    silentlyClose = True

    def __init__(
        self,
        parent: QWidget | None,
        mw: aqt.AnkiQt,
        card: Card | None,
        on_close: Callable | None = None,
        geometry_key: str | None = None,
        window_title: str | None = None,
    ) -> None:
        super().__init__(parent)
        self.mw = mw
        self._on_close = on_close
        self.GEOMETRY_KEY = geometry_key or self.GEOMETRY_KEY
        if window_title:
            self.setWindowTitle(window_title)
        self._setup_ui(card.id if card else None)
        self.show()

    def _setup_ui(self, card_id: CardId | None) -> None:
        self.mw.garbage_collect_on_dialog_finish(self)
        disable_help_button(self)
        restoreGeom(self, self.GEOMETRY_KEY)
        addCloseShortcut(self)
        setWindowIcon(self)

        self.web = AnkiWebView(title=self.TITLE)
        self.web.setVisible(False)
        self.web.load_ts_page("card-info")
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.web)
        buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
        buttons.setContentsMargins(10, 0, 10, 10)
        layout.addWidget(buttons)
        qconnect(buttons.rejected, self.reject)
        self.setLayout(layout)

        self.web.eval(
            "const cardInfo = anki.cardInfo(document.getElementById('main'));"
        )
        self.update_card(card_id)

    def update_card(self, card_id: CardId | None) -> None:
        self.web.eval(
            f"cardInfo.then((c) => c.$set({{ cardId: {json.dumps(card_id)} }}));"
        )

    def reject(self) -> None:
        if self._on_close:
            self._on_close()
        self.web.cleanup()
        self.web = None
        saveGeom(self, self.GEOMETRY_KEY)
        return QDialog.reject(self)
Exemplo n.º 14
0
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(607, 556)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.web = AnkiWebView(Dialog)
        self.web.setProperty("url", QtCore.QUrl("about:blank"))
        self.web.setObjectName("web")
        self.verticalLayout.addWidget(self.web)
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setContentsMargins(6, 6, 6, 6)
        self.horizontalLayout_3.setSpacing(8)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        spacerItem = QtWidgets.QSpacerItem(40, 20,
                                           QtWidgets.QSizePolicy.Expanding,
                                           QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_3.addItem(spacerItem)
        self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
        self.groupBox_2.setTitle("")
        self.groupBox_2.setObjectName("groupBox_2")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.groupBox_2)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.groups = QtWidgets.QRadioButton(self.groupBox_2)
        self.groups.setChecked(True)
        self.groups.setObjectName("groups")
        self.horizontalLayout_2.addWidget(self.groups)
        self.all = QtWidgets.QRadioButton(self.groupBox_2)
        self.all.setObjectName("all")
        self.horizontalLayout_2.addWidget(self.all)
        self.horizontalLayout_3.addWidget(self.groupBox_2)
        self.groupBox = QtWidgets.QGroupBox(Dialog)
        self.groupBox.setTitle("")
        self.groupBox.setObjectName("groupBox")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.month = QtWidgets.QRadioButton(self.groupBox)
        self.month.setChecked(True)
        self.month.setObjectName("month")
        self.horizontalLayout.addWidget(self.month)
        self.year = QtWidgets.QRadioButton(self.groupBox)
        self.year.setObjectName("year")
        self.horizontalLayout.addWidget(self.year)
        self.life = QtWidgets.QRadioButton(self.groupBox)
        self.life.setObjectName("life")
        self.horizontalLayout.addWidget(self.life)
        self.horizontalLayout_3.addWidget(self.groupBox)
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close)
        self.buttonBox.setObjectName("buttonBox")
        self.horizontalLayout_3.addWidget(self.buttonBox)
        self.verticalLayout.addLayout(self.horizontalLayout_3)

        self.retranslateUi(Dialog)
        self.buttonBox.accepted.connect(Dialog.accept)
        self.buttonBox.rejected.connect(Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)
Exemplo n.º 15
0
 def __init__(self, parent: QWidget, editor: Editor) -> None:
     AnkiWebView.__init__(self, title="editor")
     self.editor = editor
     self.setAcceptDrops(True)
     self._markInternal = False
     clip = self.editor.mw.app.clipboard()
     qconnect(clip.dataChanged, self._onClipboardChange)
     gui_hooks.editor_web_view_did_init(self)
Exemplo n.º 16
0
 def show(self):
     if not self.shown:
         self.web = AnkiWebView(self.mw)
         self.web.setMaximumWidth(400)
         self.shown = self.mw.addDockable(_("Card Info"), self.web)
         self.shown.connect(self.shown, SIGNAL("visibilityChanged(bool)"),
                            self._visChange)
     self._update()
Exemplo n.º 17
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self)
     self.editor = editor
     self.strip = self.editor.mw.pm.profile['stripHTML']
     self.setAcceptDrops(True)
     self._markInternal = False
     clip = self.editor.mw.app.clipboard()
     clip.dataChanged.connect(self._onClipboardChange)
 def getUserGuideTab(self):
     guide = AnkiWebView()
     guide._page.profile().setHttpUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36')
     guide._page._bridge.onCmd = attemptOpenLink
     html, url = self.getHTML()
     guide._page.setHtml(html, url)
     guide.setObjectName("tab_4")
     return guide
Exemplo n.º 19
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self)
     self.editor = editor
     self.strip = self.editor.mw.pm.profile["stripHTML"]
     self.setAcceptDrops(True)
     self._markInternal = False
     clip = self.editor.mw.app.clipboard()
     clip.dataChanged.connect(self._onClipboardChange)
Exemplo n.º 20
0
    def ui(self):
        self.web = AnkiWebView()

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.web)
        layout.addLayout(self.ui_buttons())

        return layout
Exemplo n.º 21
0
 def mouseReleaseEvent(self, evt):
     if not isMac and not isWin and evt.button() == Qt.MidButton:
         # middle click on x11; munge the clipboard before standard
         # handling
         mime = self.prepareClip(mode=QClipboard.Selection)
         AnkiWebView.mouseReleaseEvent(self, evt)
         self.restoreClip(mime, mode=QClipboard.Selection)
     else:
         AnkiWebView.mouseReleaseEvent(self, evt)
Exemplo n.º 22
0
 def mouseReleaseEvent(self, evt):
     if not isMac and not isWin and evt.button() == Qt.MidButton:
         # middle click on x11; munge the clipboard before standard
         # handling
         mime = self.prepareClip(mode=QClipboard.Selection)
         AnkiWebView.mouseReleaseEvent(self, evt)
         self.restoreClip(mime, mode=QClipboard.Selection)
     else:
         AnkiWebView.mouseReleaseEvent(self, evt)
Exemplo n.º 23
0
    def startReport(self):
        self.report = QDialog(mw)
        self.report.setWindowTitle('List of Words - Report')
        self.report.layout = QVBoxLayout(self.report)
        self.webView = AnkiWebView()
        self.report.layout.addWidget(self.webView)

        self.printButton = self.saveButton = QPushButton("Save List")
        self.printButton.pressed.connect(self.printWordList)
Exemplo n.º 24
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self, title="editor")
     self.editor = editor
     self.strip = self.editor.mw.pm.profile["stripHTML"]
     self.setAcceptDrops(True)
     self._markInternal = False
     clip = self.editor.mw.app.clipboard()
     qconnect(clip.dataChanged, self._onClipboardChange)
     gui_hooks.editor_web_view_did_init(self)
Exemplo n.º 25
0
    def addTab(self, t):
        c = self.connect
        w = QWidget()
        l = QHBoxLayout()
        l.setMargin(0)
        l.setSpacing(3)
        left = QWidget()
        # template area
        tform = aqt.forms.template.Ui_Form()
        tform.setupUi(left)
        tform.label1.setText(u" →")
        tform.label2.setText(u" →")
        tform.labelc1.setText(u" ↗")
        tform.labelc2.setText(u" ↘")
        if self.style().objectName() == "gtk+":
            # gtk+ requires margins in inner layout
            tform.tlayout1.setContentsMargins(0, 11, 0, 0)
            tform.tlayout2.setContentsMargins(0, 11, 0, 0)
            tform.tlayout3.setContentsMargins(0, 11, 0, 0)
        if len(self.cards) > 1:
            tform.groupBox_3.setTitle(_("Styling (shared between cards)"))
        c(tform.front, SIGNAL("textChanged()"), self.saveCard)
        c(tform.css, SIGNAL("textChanged()"), self.saveCard)
        c(tform.back, SIGNAL("textChanged()"), self.saveCard)
        l.addWidget(left, 5)
        # preview area
        right = QWidget()
        pform = aqt.forms.preview.Ui_Form()
        pform.setupUi(right)
        if self.style().objectName() == "gtk+":
            # gtk+ requires margins in inner layout
            pform.frontPrevBox.setContentsMargins(0, 11, 0, 0)
            pform.backPrevBox.setContentsMargins(0, 11, 0, 0)
        # for cloze notes, show that it's one of n cards
        if self.model['type'] == MODEL_CLOZE:
            cnt = len(
                self.mm.availOrds(self.model, joinFields(self.note.fields)))
            for g in pform.groupBox, pform.groupBox_2:
                g.setTitle(g.title() + _(" (1 of %d)") % max(cnt, 1))
        pform.frontWeb = AnkiWebView()
        pform.frontPrevBox.addWidget(pform.frontWeb)
        pform.backWeb = AnkiWebView()
        pform.backPrevBox.addWidget(pform.backWeb)

        def linkClicked(url):
            openLink(url)

        for wig in pform.frontWeb, pform.backWeb:
            wig.page().setLinkDelegationPolicy(QWebPage.DelegateExternalLinks)
            c(wig, SIGNAL("linkClicked(QUrl)"), linkClicked)
        l.addWidget(right, 5)
        w.setLayout(l)
        self.forms.append({'tform': tform, 'pform': pform})
        self.tabs.addTab(w, t['name'])
Exemplo n.º 26
0
    def __init__(
        self,
        parent,
        template_fmts,
        callback,
    ):
        AnkiWebView.__init__(self, parent=parent, title="minifier")
        self.set_bridge_command(self.bridge_cmd, parent)

        self.template_fmts = template_fmts
        self.callback = callback
Exemplo n.º 27
0
    def displaygrid(self, units, timeNow):
        autoModTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        currentTimeTemp = autoModTime.replace(":", "")
        currentTime = currentTimeTemp.replace(" ", "-")

        self.generate(units, timeNow, autoModTime)
        self.win = QDialog(mw)
        self.wv = AnkiWebView()
        self.wv.setHtml(self.html)
        self.wv.show()
        #self.savepng(currentTime)
        return 0
Exemplo n.º 28
0
    def _renderPreview(self) -> None:
        self.cancelPreviewTimer()

        c = self.rendered_card = self.note.ephemeral_card(
            self.ord,
            custom_note_type=self.model,
            custom_template=self.current_template(),
            fill_empty=self.fill_empty_action_toggled,
        )

        ti = self.maybeTextInput

        bodyclass = theme_manager.body_classes_for_card_ord(
            c.ord, self.night_mode_is_enabled
        )

        if not self.have_autoplayed:
            self.preview_web.eval("ankimedia._reset();")

            if not c.autoplay():
                self.preview_web.eval("ankimedia.autoplay = false;")

        if self.pform.preview_front.isChecked():
            q = ti(self.mw.prepare_card_text_for_display(c.question()))
            q = gui_hooks.card_will_show(q, c, "clayoutQuestion")
            text = q
        else:
            a = ti(self.mw.prepare_card_text_for_display(c.answer()), type="a")
            a = gui_hooks.card_will_show(a, c, "clayoutAnswer")
            text = a
            self.preview_web.eval("ankimedia.skip_front = true;")

        # use _showAnswer to avoid the longer delay
        self.preview_web.eval(f"_showAnswer({json.dumps(text)},'{bodyclass}');")
        self.preview_web.eval(
            f"_emulateMobile({json.dumps(self.mobile_emulation_enabled)});"
        )

        if not self.have_autoplayed:
            self.have_autoplayed = True

            if c.autoplay():
                AnkiWebView.setPlaybackRequiresGesture(False)
                if self.pform.preview_front.isChecked():
                    audio = c.question_av_tags()
                else:
                    audio = c.answer_av_tags()
                av_player.play_tags(audio)
            else:
                AnkiWebView.setPlaybackRequiresGesture(True)
                av_player.clear_queue_and_maybe_interrupt()

        self.updateCardNames()
Exemplo n.º 29
0
class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(531, 345)
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.fields = QtWidgets.QComboBox(Dialog)
        self.fields.setObjectName("fields")
        self.gridLayout.addWidget(self.fields, 1, 2, 1, 2)
        self.label_2 = QtWidgets.QLabel(Dialog)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 2, 1, 1, 1)
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 1, 1, 1, 1)
        self.search = QtWidgets.QLineEdit(Dialog)
        self.search.setObjectName("search")
        self.gridLayout.addWidget(self.search, 2, 2, 1, 2)
        self.verticalLayout_2.addLayout(self.gridLayout)
        self.frame = QtWidgets.QFrame(Dialog)
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.webView = AnkiWebView(self.frame)
        self.webView.setProperty("url", QtCore.QUrl("about:blank"))
        self.webView.setObjectName("webView")
        self.verticalLayout.addWidget(self.webView)
        self.verticalLayout_2.addWidget(self.frame)
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close)
        self.buttonBox.setObjectName("buttonBox")
        self.verticalLayout_2.addWidget(self.buttonBox)

        self.retranslateUi(Dialog)
        self.buttonBox.accepted.connect(Dialog.accept)
        self.buttonBox.rejected.connect(Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)
        Dialog.setTabOrder(self.fields, self.webView)
        Dialog.setTabOrder(self.webView, self.buttonBox)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_("Find Duplicates"))
        self.label_2.setText(_("Optional filter:"))
        self.label.setText(_("Search in:"))
Exemplo n.º 30
0
 def focusInEvent(self, evt):
     window = False
     if evt.reason() in (Qt.ActiveWindowFocusReason, Qt.PopupFocusReason):
         # editor area got focus again; need to tell js not to adjust cursor
         self.eval("mouseDown++;")
         window = True
     AnkiWebView.focusInEvent(self, evt)
     if evt.reason() == Qt.TabFocusReason:
         self.eval("focusField(0);")
     elif evt.reason() == Qt.BacktabFocusReason:
         n = len(self.editor.note.fields) - 1
         self.eval("focusField(%d);" % n)
     elif window:
         self.eval("mouseDown--;")
Exemplo n.º 31
0
 def focusInEvent(self, evt):
     window = False
     if evt.reason() in (Qt.ActiveWindowFocusReason, Qt.PopupFocusReason):
         # editor area got focus again; need to tell js not to adjust cursor
         self.eval("mouseDown++;")
         window = True
     AnkiWebView.focusInEvent(self, evt)
     if evt.reason() == Qt.TabFocusReason:
         self.eval("focusField(0);")
     elif evt.reason() == Qt.BacktabFocusReason:
         n = len(self.editor.note.fields) - 1
         self.eval("focusField(%d);" % n)
     elif window:
         self.eval("mouseDown--;")
Exemplo n.º 32
0
def miMessage(text, parent=False):
    title = "Migaku"
    if parent is False:
        parent = aqt.mw.app.activeWindow() or aqt.mw
    icon = QIcon(join(addon_path, 'icons', 'migaku.png'))
    mb = QMessageBox(parent)
    mb.setWindowIcon(icon)
    mb.setWindowTitle(title)
    cb = QCheckBox("Don't show me the welcome screen again.")
    wv = AnkiWebView()
    wv._page._bridge.onCmd = attemptOpenLink
    wv.setFixedSize(680, 450)
    wv.page().setHtml(text)
    wide = QWidget()
    wide.setFixedSize(18, 18)
    mb.layout().addWidget(wv, 0, 1)
    mb.layout().addWidget(wide, 0, 2)
    mb.layout().setColumnStretch(0, 3)
    mb.layout().addWidget(cb, 1, 1)
    b = mb.addButton(QMessageBox.Ok)
    b.setFixedSize(100, 30)
    b.setDefault(True)
    mb.exec_()
    wv.deleteLater()
    if cb.isChecked():
        return True
    else:
        return False
Exemplo n.º 33
0
    def __init__(self):
        self.mw = mw
        self.models = self.mw.col.models.all()

        self.window = QDialog(mw)
        self.window.setWindowTitle('List of Words - Choose')
        self.window.layout = QVBoxLayout(self.window)
        self.webView = AnkiWebView()
        self.window.layout.addWidget(self.webView)

        report = self.getHeisingStats()
        self.webView.stdHtml(report)

        self.window.show()
        self.window.exec_()
Exemplo n.º 34
0
    def __init__(self, parent):
        AnkiWebView.__init__(self, title = "Extractor")

        self.parent = parent
        addon_id = ADDON_NAME

        self.set_bridge_command(self._on_bridge_cmd, self)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.stdHtml(f"""<html><body id="htmlcontent"></body></html>""",
        css = [f"../_addons/{addon_id}/web/style.css"],
        js = [f"../_addons/{addon_id}/web/content.js",
              f"../_addons/{addon_id}/web/tinymce/tinymce.min.js"])

        self.eval(f"""var absolute_base_url = "http://127.0.0.1:{mw.mediaServer.getPort()}/";""")
Exemplo n.º 35
0
def onhanziStats():
    mw.progress.start(immediate=True)
    rep = genhanziStats()
    d = QDialog(mw)
    l = QVBoxLayout()
    w = AnkiWebView()
    l.addWidget(w)
    css = "font{word-wrap:break-word;} div{display:none;}"
    w.stdHtml(rep, css)
    d.setLayout(l)
    d.resize(500, 400)
    restoreGeom(d, "hanzistats")
    mw.progress.finish()
    d.exec_()
    saveGeom(d, "hanzistats")
Exemplo n.º 36
0
    def __init__(self,reader):
        GenericProfile.__init__(self,reader)

        self.dockKanji = QtGui.QDockWidget(reader)
        self.dockKanji.setObjectName(fromUtf8("dockKanji"))
        self.dockWidgetContents = QtGui.QWidget()
        self.dockWidgetContents.setObjectName(fromUtf8("dockWidgetContents"))
        self.verticalLayout = QtGui.QVBoxLayout(self.dockWidgetContents)
        self.verticalLayout.setObjectName(fromUtf8("verticalLayout"))
        self.textField = AnkiWebView()
        self.textField.setAcceptDrops(False)
        self.textField.setObjectName("textField")
        self.verticalLayout.addWidget(self.textField)
        self.horizontalLayout_3 = QtGui.QHBoxLayout()
        self.horizontalLayout_3.setObjectName(fromUtf8("horizontalLayout_3"))
        self.verticalLayout.addLayout(self.horizontalLayout_3)
        self.dockKanji.setWidget(self.dockWidgetContents)
        reader.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockKanji)
        self.dockKanji.visibilityChanged.connect(self.onVisibilityChanged)
        self.dockKanji.setWindowTitle(translate("MainWindowReader", "Kanji", None))
        self.textField.setLinkHandler(self.onAnchorClicked)


        # menu entries to toggle visibility of the Kanji dock
        self.actionToggleKanji = QtGui.QAction(reader)
        self.actionToggleKanji.setCheckable(True)
        self.actionToggleKanji.setObjectName("actionToggleKanji")
        self.actionToggleKanji.setText("&Kanji")
        self.actionToggleKanji.setToolTip("Toggle Kanji")
        reader.menuView.insertAction(reader.menuView.actions()[2],self.actionToggleKanji)
        QtCore.QObject.connect(self.actionToggleKanji, QtCore.SIGNAL("toggled(bool)"), self.dockKanji.setVisible)
Exemplo n.º 37
0
    def __init__(self,reader):
        GenericProfile.__init__(self,reader)
        self.history = []
        self.currentIndex = 0
        self.dockVocab = QtGui.QDockWidget(reader)
        self.dockVocab.setObjectName(fromUtf8("dockVocab"))
        self.dockWidgetContents = QtGui.QWidget()
        self.dockWidgetContents.setObjectName(fromUtf8("dockWidgetContents"))
        self.verticalLayout = QtGui.QVBoxLayout(self.dockWidgetContents)
        self.verticalLayout.setObjectName(fromUtf8("verticalLayout"))
        self.previousExpression = None
        self.textField = AnkiWebView()
        self.textField.setAcceptDrops(False)
        self.textField.setObjectName("textField")
        self.keyFilter = VocabKeyFilter()
        self.keyFilter.obj = self
        self.keyFilter.textField = self.textField
        self.textField.installEventFilter(self.keyFilter)
        self.verticalLayout.addWidget(self.textField)
        self.dockVocab.setWidget(self.dockWidgetContents)
        reader.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockVocab)
        self.dockVocab.visibilityChanged.connect(self.onVisibilityChanged)
        self.dockVocab.setWindowTitle(translate("MainWindowReader", "Vocabulary", None))
        self.textField.setLinkHandler(self.onAnchorClicked)

        # menu entries to toggle visibility of the vocabulary dock
        self.actionToggleVocab = QtGui.QAction(reader)
        self.actionToggleVocab.setCheckable(True)
        self.actionToggleVocab.setObjectName("actionToggleVocab")
        self.actionToggleVocab.setText("&Vocabulary")
        self.actionToggleVocab.setToolTip("Toggle vocabulary")
        reader.menuView.insertAction(reader.menuView.actions()[2],self.actionToggleVocab)
        QtCore.QObject.connect(self.actionToggleVocab, QtCore.SIGNAL("toggled(bool)"), self.dockVocab.setVisible)
        self.dockVocab.installEventFilter(self.reader.keyFilter)
Exemplo n.º 38
0
 def onRevlog(self):
     data = self._revlogData()
     d = QDialog(self)
     l = QVBoxLayout()
     l.setMargin(0)
     w = AnkiWebView()
     l.addWidget(w)
     w.stdHtml(data)
     bb = QDialogButtonBox(QDialogButtonBox.Close)
     l.addWidget(bb)
     bb.connect(bb, SIGNAL("rejected()"), d, SLOT("reject()"))
     d.setLayout(l)
     d.setWindowModality(Qt.WindowModal)
     d.resize(500, 400)
     restoreGeom(d, "revlog")
     d.exec_()
     saveGeom(d, "revlog")
Exemplo n.º 39
0
Arquivo: stats.py Projeto: ChYi/ankiqt
 def show(self):
     if not self.shown:
         self.web = AnkiWebView(self.mw)
         self.web.setMaximumWidth(400)
         self.shown = self.mw.addDockable(_("Card Info"), self.web)
         self.shown.connect(self.shown, SIGNAL("visibilityChanged(bool)"),
                            self._visChange)
     self._update()
Exemplo n.º 40
0
Arquivo: stats.py Projeto: ChYi/ankiqt
class CardStats(object):
    def __init__(self, mw):
        self.mw = mw
        self.shown = False
        addHook("showQuestion", self._update)
        addHook("deckClosing", self.hide)
        addHook("reviewCleanup", self.hide)

    def show(self):
        if not self.shown:
            self.web = AnkiWebView(self.mw)
            self.web.setMaximumWidth(400)
            self.shown = self.mw.addDockable(_("Card Info"), self.web)
            self.shown.connect(self.shown, SIGNAL("visibilityChanged(bool)"),
                               self._visChange)
        self._update()

    def hide(self):
        if self.shown:
            self.mw.rmDockable(self.shown)
            self.shown = None

    def _visChange(self, vis):
        if not vis:
            # schedule removal for after evt has finished
            self.mw.progress.timer(100, self.hide, False)

    def _update(self):
        if not self.shown:
            return
        txt = ""
        r = self.mw.reviewer
        d = self.mw.deck
        if r.card:
            txt += _("<h1>Current</h1>")
            txt += d.cardStats(r.card)
        lc = r.lastCard()
        if lc:
            txt += _("<h1>Last</h1>")
            txt += d.cardStats(lc)
        if not txt:
            txt = _("No current card or last card.")
        self.web.setHtml("""
<html><head>
<style>table { font-size: 12px; } h1 { font-size: 14px; }</style>
</head><body><center>%s</center></body></html>"""%txt)
Exemplo n.º 41
0
def onKanjiStats():
    mw.progress.start(immediate=True)
    rep = genKanjiStats()
    d = QDialog(mw)
    l = QVBoxLayout()
    l.setMargin(0)
    w = AnkiWebView()
    l.addWidget(w)
    w.stdHtml(rep)
    bb = QDialogButtonBox(QDialogButtonBox.Close)
    l.addWidget(bb)
    bb.connect(bb, SIGNAL("rejected()"), d, SLOT("reject()"))
    d.setLayout(l)
    d.resize(500, 400)
    restoreGeom(d, "kanjistats")
    mw.progress.finish()
    d.exec_()
    saveGeom(d, "kanjistats")
Exemplo n.º 42
0
def onhanziStats():
    mw.progress.start(immediate=True)
    rep = genhanziStats()
    d = QDialog(mw)
    l = QVBoxLayout()
    l.setMargin(0)
    w = AnkiWebView()
    l.addWidget(w)
    css = "font{word-wrap:break-word;} div{display:none;}"
    w.stdHtml(rep, css)
    bb = QDialogButtonBox(QDialogButtonBox.Close)
    l.addWidget(bb)
    bb.connect(bb, SIGNAL("rejected()"), d, SLOT("reject()"))
    d.setLayout(l)
    d.resize(500, 400)
    restoreGeom(d, "hanzistats")
    mw.progress.finish()
    d.exec_()
    saveGeom(d, "hanzistats")
Exemplo n.º 43
0
 def showCardInfo(self):
     if not self.card:
         return
     info, cs = self._cardInfoData()
     reps = self._revlogData(cs)
     d = QDialog(self)
     l = QVBoxLayout()
     l.setMargin(0)
     w = AnkiWebView()
     l.addWidget(w)
     w.stdHtml(info + "<p>" + reps)
     bb = QDialogButtonBox(QDialogButtonBox.Close)
     l.addWidget(bb)
     bb.connect(bb, SIGNAL("rejected()"), d, SLOT("reject()"))
     d.setLayout(l)
     d.setWindowModality(Qt.WindowModal)
     d.resize(500, 400)
     restoreGeom(d, "revlog")
     d.exec_()
     saveGeom(d, "revlog")
Exemplo n.º 44
0
 def __init__(self, reviewer, card, parent=None):
     QDialog.__init__(self, parent=None)
     self.card = card
     self.reviewer = reviewer
     self.mw = reviewer.mw
     self.col = self.mw.col
     info, cs = self._cardInfoData()
     reps = self._revlogData(cs)
     l = QVBoxLayout()
     l.setMargin(0)
     w = AnkiWebView()
     l.addWidget(w)
     w.stdHtml(info + "<p>" + reps)
     bb = QDialogButtonBox(QDialogButtonBox.Close)
     l.addWidget(bb)
     bb.connect(bb, SIGNAL("rejected()"), self, SLOT("reject()"))
     self.setLayout(l)
     self.setWindowModality(Qt.WindowModal)
     self.resize(500, 400)
     restoreGeom(self, "CardStatShowDialog")
Exemplo n.º 45
0
def showHTML(html, modality=Qt.WindowModal):
	m = QMainWindow(mw.app.activeWindow())
	d = QDialog(m)
	l = QVBoxLayout()
	l.setMargin(0)
	w = AnkiWebView()
	l.addWidget(w)
	bb = QDialogButtonBox(QDialogButtonBox.Close)
	l.addWidget(bb)
	bb.connect(bb, SIGNAL("rejected()"), d, SLOT("reject()"))
	d.setLayout(l)
	d.setWindowModality(modality)
	d.resize(500, 400) 
	restoreGeom(d, "htmlview")
	w.stdHtml(html)
	if modality == Qt.WindowModal :
		d.exec_()
	else :
		d.show()
	saveGeom(d, "htmlview")
Exemplo n.º 46
0
    def updateWindow(self, html):

        if html is None:
            return False

        # build view
        webview = AnkiWebView()
        webview.stdHtml(html, mw.sharedCSS)
        webview.setLinkHandler(self.links)

        # Clear old layout
        if self.__layout:
            QObjectCleanupHandler().add(self.__layout)

        # build layout
        self.__layout = QVBoxLayout()
        self.__layout.setMargin(0)
        self.__layout.addWidget(webview)

        # Update window
        self.setLayout(self.__layout)
        self.update()
Exemplo n.º 47
0
 def dropEvent(self, evt):
     oldmime = evt.mimeData()
     # coming from this program?
     if evt.source():
         if oldmime.hasHtml():
             mime = QMimeData()
             mime.setHtml(_filterHTML(oldmime.html()))
         else:
             # old qt on linux won't give us html when dragging an image;
             # in that case just do the default action (which is to ignore
             # the drag)
             return AnkiWebView.dropEvent(self, evt)
     else:
         mime = self._processMime(oldmime)
     # create a new event with the new mime data and run it
     new = QDropEvent(evt.pos(), evt.possibleActions(), mime,
                      evt.mouseButtons(), evt.keyboardModifiers())
     evt.accept()
     QWebView.dropEvent(self, new)
     # tell the drop target to take focus so the drop contents are saved
     self.eval("dropTarget.focus();")
Exemplo n.º 48
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self, parent)
     self.editor = editor
     self.errtxt = _("An error occured while opening %s")
     self.strip = self.editor.mw.config["stripHTML"]
Exemplo n.º 49
0
class KanjiProfile(GenericProfile):
    name = "kanji"
    descriptor = "KANJI IN THIS TEXT"
    displayedName = "Kanji"
    languages = ["japanese"]
    sortIndex = 2
    allowedTags = ['character', 'onyomi', 'kunyomi', 'glossary','ongroup','words']

    def __init__(self,reader):
        GenericProfile.__init__(self,reader)

        self.dockKanji = QtGui.QDockWidget(reader)
        self.dockKanji.setObjectName(fromUtf8("dockKanji"))
        self.dockWidgetContents = QtGui.QWidget()
        self.dockWidgetContents.setObjectName(fromUtf8("dockWidgetContents"))
        self.verticalLayout = QtGui.QVBoxLayout(self.dockWidgetContents)
        self.verticalLayout.setObjectName(fromUtf8("verticalLayout"))
        self.textField = AnkiWebView()
        self.textField.setAcceptDrops(False)
        self.textField.setObjectName("textField")
        self.verticalLayout.addWidget(self.textField)
        self.horizontalLayout_3 = QtGui.QHBoxLayout()
        self.horizontalLayout_3.setObjectName(fromUtf8("horizontalLayout_3"))
        self.verticalLayout.addLayout(self.horizontalLayout_3)
        self.dockKanji.setWidget(self.dockWidgetContents)
        reader.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockKanji)
        self.dockKanji.visibilityChanged.connect(self.onVisibilityChanged)
        self.dockKanji.setWindowTitle(translate("MainWindowReader", "Kanji", None))
        self.textField.setLinkHandler(self.onAnchorClicked)


        # menu entries to toggle visibility of the Kanji dock
        self.actionToggleKanji = QtGui.QAction(reader)
        self.actionToggleKanji.setCheckable(True)
        self.actionToggleKanji.setObjectName("actionToggleKanji")
        self.actionToggleKanji.setText("&Kanji")
        self.actionToggleKanji.setToolTip("Toggle Kanji")
        reader.menuView.insertAction(reader.menuView.actions()[2],self.actionToggleKanji)
        QtCore.QObject.connect(self.actionToggleKanji, QtCore.SIGNAL("toggled(bool)"), self.dockKanji.setVisible)


    def onVisibilityChanged(self,visible):
        self.actionToggleKanji.setChecked(self.dockKanji.isVisible())

    def onAnchorClicked(self, url):
        command, index = url.split(':')
        if command == "jisho":
            self.reader.profiles["vocabulary"].onQuery([index])
            #url = QtCore.QUrl(self.reader.preferences["linkToKanji"].format(index))
            #QtGui.QDesktopServices().openUrl(url)
        else:
            index = int(index)
            commands = command.split("_")
            profile = commands.pop(0)
            self.runCommand(commands,self.definitions[index])

    def onLookup(self,d,lengthMatched):
        if self.dockKanji.isVisible():
            if 'japanese' in self.reader.languages:
                if lengthMatched == 0:
                    self.definitions = self.reader.languages['japanese'].findCharacters(d['contentSample'][0])
                    if len(self.definitions) > 0:
                        lengthMatched = 1
                else:
                    self.definitions = self.reader.languages['japanese'].findCharacters(d['contentSample'][:lengthMatched])
                self.updateDefinitions()
            self.reader.updateVocabDefs('kanji')
        return lengthMatched

    def onShowDialogPreferences(self,dialog):
        GenericProfile.onShowDialogPreferences(self,dialog)

    def runCommand(self,cmd,definition):
        if cmd[0] == "copy":
            QtGui.QApplication.clipboard().setText(u'{character}\t{kunyomi}\t{onyomi}\t{glossary}'.format(**definition))
        elif cmd[0] =="add":
            self.addFact(definition)
        elif cmd[0] == "addgroup":
            kanjigroups = os.path.join(self.reader.anki.collection().media.dir(),"Yomichan","KanjiGroups")
            if os.path.exists(kanjigroups):
                filename = os.path.join(kanjigroups,definition['ongroup']+".txt")
                with open(filename,'w') as fp:
                    content = u"""### REGEXP ###
.*[{0}]###v###
### SHUFFLE THIS TEXT ###""".format(definition['ongroup'])
                    fp.write(content.encode('utf-8'))
                    fp.close()
            d = dict()
            d['contentSample'] = definition['ongroup']
            self.onLookup(d,len(d['contentSample']))
            self.reader.profiles["vocabulary"].onQuery(list(definition['ongroup']))

    def markup(self, definition):
        allCards = self.reader.plugin.fetchAllCards()
        words = u",".join([x for x in allCards["vocabulary"].keys() if definition['character'] in x])
        return {
        'character': definition['character'],
        'onyomi': definition['onyomi'],
        'kunyomi': definition['kunyomi'],
        'glossary': definition['glossary'],
        'summary': definition['character'],
        'ongroup': definition['ongroup'],
        'words': words
    }

    def buildDefBody(self, definition, index, allowOverwrite):
        links = '<a href="kanji_copy:{0}"><img src="qrc:///img/img/icon_copy_definition.png" align="right"></a>'.format(index)
        if (self.ankiIsFactValid('kanji', definition, index)):
            links += '<a href="kanji_add:{0}"><img src="qrc:///img/img/icon_add_expression.png" align="right"></a>'.format(index)

        readings = ', '.join([definition['kunyomi'], definition['onyomi']])
        if definition['ongroup'] is not None:
            ongroup = u"""<a style="text-decoration:none;" href="kanji_addgroup:{0}">{1}</a>""".format(index,definition['ongroup'])
        else:
            ongroup = ''
        html = u"""
            <span class="links">{0}</span>
            <span class="expression"><a href="jisho:{1}">{1}</a><br></span>
            <span class="reading">[{2}]<br></span>
            <span class="glossary">{3}<br></span>
            <span class="ongroup">{4}<br></span>
            <br clear="all">""".format(links, definition['character'], readings, definition['glossary'],ongroup)

        return html
Exemplo n.º 50
0
class Browser(QMainWindow):

    def __init__(self, mw):
        QMainWindow.__init__(self, mw)
        applyStyles(self)
        self.mw = mw
        self.col = self.mw.col
        self.currentRow = None
        self.lastFilter = ""
        self.form = aqt.forms.browser.Ui_Dialog()
        self.form.setupUi(self)
        restoreGeom(self, "editor", 0)
        restoreState(self, "editor")
        restoreSplitter(self.form.splitter_2, "editor2")
        restoreSplitter(self.form.splitter, "editor3")
        self.form.splitter_2.setChildrenCollapsible(False)
        self.form.splitter.setChildrenCollapsible(False)
        self.card = None
        self.setupToolbar()
        self.setupColumns()
        self.setupTable()
        self.setupMenus()
        self.setupSearch()
        self.setupTree()
        self.setupHeaders()
        self.setupHooks()
        self.setupEditor()
        self.updateFont()
        self.onUndoState(self.mw.form.actionUndo.isEnabled())
        self.form.searchEdit.setFocus()
        self.show()
        self.form.searchEdit.setText("deck:current is:recent")
        self.form.searchEdit.selectAll()
        self.onSearch()

    def setupToolbar(self):
        self.toolbarWeb = AnkiWebView()
        self.toolbarWeb.setFixedHeight(32)
        self.toolbar = BrowserToolbar(self.mw, self.toolbarWeb, self)
        self.form.verticalLayout_3.insertWidget(0, self.toolbarWeb)
        self.toolbar.draw()

    def setupMenus(self):
        # actions
        c = self.connect; f = self.form; s = SIGNAL("triggered()")
        c(f.actionReposition, s, self.reposition)
        c(f.actionReschedule, s, self.reschedule)
        c(f.actionCram, s, self.cram)
        c(f.actionChangeModel, s, self.onChangeModel)
        # edit
        c(f.actionOptions, s, self.onOptions)
        c(f.actionUndo, s, self.mw.onUndo)
        c(f.actionInvertSelection, s, self.invertSelection)
        c(f.actionSelectNotes, s, self.selectNotes)
        c(f.actionFindReplace, s, self.onFindReplace)
        c(f.actionFindDuplicates, s, self.onFindDupes)
        # jumps
        c(f.actionPreviousCard, s, self.onPreviousCard)
        c(f.actionNextCard, s, self.onNextCard)
        c(f.actionFind, s, self.onFind)
        c(f.actionNote, s, self.onNote)
        c(f.actionTags, s, self.onTags)
        c(f.actionCardList, s, self.onCardList)
        # help
        c(f.actionGuide, s, self.onHelp)
        runHook('browser.setupMenus', self)

    def updateFont(self):
        self.form.tableView.setFont(QFont(
            self.mw.pm.profile['editFontFamily'],
            self.mw.pm.profile['editFontSize']))
        self.form.tableView.verticalHeader().setDefaultSectionSize(
            self.mw.pm.profile['editLineSize'])

    def closeEvent(self, evt):
        saveSplitter(self.form.splitter_2, "editor2")
        saveSplitter(self.form.splitter, "editor3")
        self.editor.saveNow()
        self.editor.setNote(None)
        saveGeom(self, "editor")
        saveState(self, "editor")
        saveHeader(self.form.tableView.horizontalHeader(), "editor")
        self.col.conf['activeCols'] = self.model.activeCols
        self.hide()
        aqt.dialogs.close("Browser")
        self.teardownHooks()
        self.mw.maybeReset()
        evt.accept()

    def keyPressEvent(self, evt):
        "Show answer on RET or register answer."
        if evt.key() == Qt.Key_Escape:
            self.close()
        elif self.mw.app.focusWidget() == self.form.tree:
            if evt.key() in (Qt.Key_Return, Qt.Key_Enter):
                item = self.form.tree.currentItem()
                self.onTreeClick(item, 0)

    def setupColumns(self):
        self.columns = [
            ('question', _("Question")),
            ('answer', _("Answer")),
            ('template', _("Card")),
            ('deck', _("Card Deck")),
            ('ndeck', _("Note Deck")),
            ('noteFld', _("Sort Field")),
            ('noteCrt', _("Created")),
            ('noteMod', _("Edited")),
            ('cardMod', _("Reviewed")),
            ('cardDue', _("Due")),
            ('cardIvl', _("Interval")),
            ('cardEase', _("Ease")),
            ('cardReps', _("Reviews")),
            ('cardLapses', _("Lapses")),
        ]

    # Searching
    ######################################################################

    def setupSearch(self):
        self.filterTimer = None
        self.connect(self.form.searchButton,
                     SIGNAL("clicked()"),
                     self.onSearch)
        self.connect(self.form.searchEdit,
                     SIGNAL("returnPressed()"),
                     self.onSearch)
        self.setTabOrder(self.form.searchEdit, self.form.tableView)
        self.compModel = QStringListModel()
        self.compModel.setStringList(self.mw.pm.profile['searchHistory'])
        self.searchComp = QCompleter(self.compModel, self.form.searchEdit)
        self.searchComp.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.searchComp.setCaseSensitivity(Qt.CaseInsensitive)
        self.form.searchEdit.setCompleter(self.searchComp)

    def onSearch(self, reset=True):
        "Careful: if reset is true, the current note is saved."
        txt = unicode(self.form.searchEdit.text()).strip()
        sh = self.mw.pm.profile['searchHistory']
        if txt not in sh:
            sh.insert(0, txt)
            sh = sh[:30]
            self.compModel.setStringList(sh)
            self.mw.pm.profile['searchHistory'] = sh
        self.model.search(txt, reset)
        if not self.model.cards:
            # no row change will fire
            self.onRowChanged(None, None)
            # somewhat distracting
            # txt = _("No matches found.")
            # if not self.mw.pm.profile['fullSearch']:
            #     txt += "<p>" + _(
            #     _("If your cards have formatting, you may want <br>"
            #       "to enable 'search within formatting' in the<br>"
            #       "browser options."))
            # tooltip(txt)

    def updateTitle(self):
        selected = len(self.form.tableView.selectionModel().selectedRows())
        cur = len(self.model.cards)
        self.setWindowTitle(ngettext("Browser (%(cur)d card shown; %(sel)s)",
                                     "Browser (%(cur)d cards shown; %(sel)s)",
                                 cur) % {
            "cur": cur,
            "sel": ngettext("%d selected", "%d selected", selected) % selected
            })
        return selected

    def onReset(self):
        self.editor.setNote(None)
        self.onSearch()

    # Table view & editor
    ######################################################################

    def setupTable(self):
        self.model = DataModel(self)
        self.form.tableView.setSortingEnabled(True)
        self.form.tableView.setModel(self.model)
        self.form.tableView.selectionModel()
        self.form.tableView.setItemDelegate(StatusDelegate(self, self.model))
        self.connect(self.form.tableView.selectionModel(),
                     SIGNAL("selectionChanged(QItemSelection,QItemSelection)"),
                     self.onRowChanged)

    def setupEditor(self):
        self.editor = aqt.editor.Editor(
            self.mw, self.form.fieldsArea, self)
        self.editor.stealFocus = False

    def onRowChanged(self, current, previous):
        "Update current note and hide/show editor."
        show = self.model.cards and self.updateTitle() == 1
        self.form.splitter.widget(1).setShown(not not show)
        if not show:
            self.editor.setNote(None)
        else:
            self.card = self.model.getCard(
                self.form.tableView.selectionModel().currentIndex())
            self.editor.setNote(self.card.note())
            self.editor.card = self.card
        self.toolbar.draw()

    def refreshCurrentCard(self, note):
        self.model.refreshNote(note)

    # Headers & sorting
    ######################################################################

    def setupHeaders(self):
        vh = self.form.tableView.verticalHeader()
        hh = self.form.tableView.horizontalHeader()
        if not isWin:
            vh.hide()
            hh.show()
        restoreHeader(hh, "editor")
        hh.setHighlightSections(False)
        hh.setMinimumSectionSize(50)
        hh.setMovable(True)
        self.setColumnSizes()
        hh.setContextMenuPolicy(Qt.CustomContextMenu)
        hh.connect(hh, SIGNAL("customContextMenuRequested(QPoint)"),
                   self.onHeaderContext)
        self.setSortIndicator()
        hh.connect(hh, SIGNAL("sortIndicatorChanged(int, Qt::SortOrder)"),
                   self.onSortChanged)

    def onSortChanged(self, idx, ord):
        type = self.model.activeCols[idx]
        noSort = ("question", "answer", "template", "deck", "ndeck")
        if type in noSort:
            showInfo(_("Sorting on this column is not supported. Please "
                       "choose another."))
            type = self.col.conf['sortType']
        if self.col.conf['sortType'] != type:
            self.col.conf['sortType'] = type
            # default to descending for non-text fields
            if type == "noteFld":
                ord = not ord
            self.col.conf['sortBackwards'] = ord
            self.onSearch()
        else:
            if self.col.conf['sortBackwards'] != ord:
                self.col.conf['sortBackwards'] = ord
                self.model.reverse()
        self.setSortIndicator()

    def setSortIndicator(self):
        hh = self.form.tableView.horizontalHeader()
        type = self.col.conf['sortType']
        if type not in self.model.activeCols:
            hh.setSortIndicatorShown(False)
            return
        idx = self.model.activeCols.index(type)
        if self.col.conf['sortBackwards']:
            ord = Qt.DescendingOrder
        else:
            ord = Qt.AscendingOrder
        hh.blockSignals(True)
        hh.setSortIndicator(idx, ord)
        hh.blockSignals(False)
        hh.setSortIndicatorShown(True)

    def onHeaderContext(self, pos):
        gpos = self.form.tableView.mapToGlobal(pos)
        m = QMenu()
        for type, name in self.columns:
            a = m.addAction(name)
            a.setCheckable(True)
            a.setChecked(type in self.model.activeCols)
            a.connect(a, SIGNAL("toggled(bool)"),
                      lambda b, t=type: self.toggleField(t))
        m.exec_(gpos)

    def toggleField(self, type):
        self.model.beginReset()
        if type in self.model.activeCols:
            self.model.activeCols.remove(type)
        else:
            self.model.activeCols.append(type)
        self.setColumnSizes()
        # sorted field may have been hidden
        self.setSortIndicator()
        self.model.endReset()

    def setColumnSizes(self):
        hh = self.form.tableView.horizontalHeader()
        for c, i in enumerate(self.model.activeCols):
            if c == len(self.model.activeCols) - 1:
                hh.setResizeMode(c, QHeaderView.Stretch)
            else:
                hh.setResizeMode(c, QHeaderView.Interactive)

    # Filter tree
    ######################################################################

    class CallbackItem(QTreeWidgetItem):
        def __init__(self, name, onclick):
            QTreeWidgetItem.__init__(self, [name])
            self.onclick = onclick

    def setupTree(self):
        self.connect(
            self.form.tree, SIGNAL("itemClicked(QTreeWidgetItem*,int)"),
            self.onTreeClick)
        p = QPalette()
        p.setColor(QPalette.Base, QColor("#d6dde0"))
        self.form.tree.setPalette(p)
        self.buildTree()

    def buildTree(self):
        self.form.tree.clear()
        root = self.form.tree.invisibleRootItem()
        self._systemTagTree(root)
        self._decksTree(root)
        self._userTagTree(root)
        self.form.tree.expandToDepth(0)
        self.form.tree.setIndentation(15)

    def onTreeClick(self, item, col):
        if getattr(item, 'onclick', None):
            item.onclick()

    def setFilter(self, *args):
        if len(args) == 1:
            txt = args[0]
        else:
            txt = ""
            items = []
            for c, a in enumerate(args):
                if c % 2 == 0:
                    txt += a + ":"
                else:
                    txt += a
                    if " " in txt:
                        txt = "'%s'" % txt
                    items.append(txt)
                    txt = ""
            txt = " ".join(items)
        if self.mw.app.keyboardModifiers() & Qt.ControlModifier:
            cur = unicode(self.form.searchEdit.text())
            if cur:
                txt = cur + " " + txt
        self.form.searchEdit.setText(txt)
        self.onSearch()

    def _systemTagTree(self, root):
        tags = (
            (_("Whole Collection"), "anki", ""),
            (_("Current Deck"), "deck16", "deck:current"),
            (_("New"), "plus16.png", "is:new"),
            (_("Learning"), "stock_new_template_red.png", "is:learn"),
            (_("Review"), "clock16.png", "is:review"),
            (_("Marked"), "star16.png", "tag:marked"),
            (_("Suspended"), "media-playback-pause.png", "is:suspended"),
            (_("Leech"), "emblem-important.png", "tag:leech"))
        for name, icon, cmd in tags:
            item = self.CallbackItem(
                name, lambda c=cmd: self.setFilter(c))
            item.setIcon(0, QIcon(":/icons/" + icon))
            root.addChild(item)
        return root

    def _userTagTree(self, root):
        for t in sorted(self.col.tags.all()):
            item = self.CallbackItem(
                t, lambda t=t: self.setFilter("tag", t))
            item.setIcon(0, QIcon(":/icons/anki-tag.png"))
            root.addChild(item)

    def _decksTree(self, root):
        grps = self.col.sched.deckDueTree()
        def fillGroups(root, grps, head=""):
            for g in grps:
                item = self.CallbackItem(
                g[0], lambda g=g: self.setFilter(
                    "deck", head+g[0]))
                item.setIcon(0, QIcon(":/icons/deck16.png"))
                root.addChild(item)
                fillGroups(item, g[4], g[0]+"::")
        fillGroups(root, grps)

    # Info
    ######################################################################

    def showCardInfo(self):
        if not self.card:
            return
        info, cs = self._cardInfoData()
        reps = self._revlogData(cs)
        d = QDialog(self)
        l = QVBoxLayout()
        l.setMargin(0)
        w = AnkiWebView()
        l.addWidget(w)
        w.stdHtml(info + "<p>" + reps)
        bb = QDialogButtonBox(QDialogButtonBox.Close)
        l.addWidget(bb)
        bb.connect(bb, SIGNAL("rejected()"), d, SLOT("reject()"))
        d.setLayout(l)
        d.setWindowModality(Qt.WindowModal)
        d.resize(500, 400)
        restoreGeom(d, "revlog")
        d.exec_()
        saveGeom(d, "revlog")

    def _cardInfoData(self):
        from anki.stats import CardStats
        cs = CardStats(self.col, self.card)
        rep = cs.report()
        rep = "<style>table * { font-size: 12px; }</style>" + rep
        m = self.card.model()
        rep = """
<div style='width: 400px; margin: 0 auto 0;
border: 1px solid #000; padding: 3px; '>%s</div>""" % rep
        return rep, cs

    def onCardLink(self, url):
        if url == "sort":
            self.onChangeSortField()
        else:
            self.onRevlog()

    def onChangeSortField(self):
        from aqt.utils import chooseList
        m = self.card.model()
        fields = [f['name'] for f in m['flds']]
        mm = self.col.models
        idx = chooseList(_("Choose field to sort this model by:"),
                         fields, mm.sortIdx(m))
        if idx != mm.sortIdx(m):
            self.mw.progress.start()
            mm.setSortIdx(m, idx)
            self.mw.progress.finish()
            self.onSearch()

    def onRevlog(self):
        data = self._revlogData()
        d = QDialog(self)
        l = QVBoxLayout()
        l.setMargin(0)
        w = AnkiWebView()
        l.addWidget(w)
        w.stdHtml(data)
        bb = QDialogButtonBox(QDialogButtonBox.Close)
        l.addWidget(bb)
        bb.connect(bb, SIGNAL("rejected()"), d, SLOT("reject()"))
        d.setLayout(l)
        d.setWindowModality(Qt.WindowModal)
        d.resize(500, 400)
        restoreGeom(d, "revlog")
        d.exec_()
        saveGeom(d, "revlog")

    def _revlogData(self, cs):
        entries = self.mw.col.db.all(
            "select id/1000.0, ease, ivl, factor, time/1000.0, type "
            "from revlog where cid = ?", self.card.id)
        if not entries:
            return ""
        s = "<table width=100%%><tr><th align=left>%s</th>" % _("Date")
        s += ("<th align=right>%s</th>" * 5) % (
            _("Type"), _("Ease"), _("Interval"), _("Factor"), _("Time"))
        cnt = 0
        for (date, ease, ivl, factor, taken, type) in reversed(entries):
            cnt += 1
            s += "<tr><td>%s</td>" % time.strftime(_("<b>%Y-%m-%d</b> @ %H:%M"),
                                                   time.localtime(date))
            tstr = [_("Learn"), _("Review"), _("Relearn"), _("Cram"),
                    _("Resched")][type]
            import anki.stats as st
            fmt = "<span style='color:%s'>%s</span>"
            if type == 0:
                tstr = fmt % (st.colLearn, tstr)
            elif type == 1:
                tstr = fmt % (st.colMature, tstr)
            elif type == 2:
                tstr = fmt % (st.colRelearn, tstr)
            elif type == 3:
                tstr = fmt % (st.colCram, tstr)
            else:
                tstr = fmt % ("#000", tstr)
            if ease == 1:
                ease = fmt % (st.colRelearn, ease)
            if ivl == 0:
                ivl = _("0d")
            elif ivl > 0:
                ivl = fmtTimeSpan(ivl*86400, short=True)
            else:
                ivl = cs.time(-ivl)
            s += ("<td align=right>%s</td>" * 5) % (
                tstr,
                ease, ivl,
                "%d%%" % (factor/10) if factor else "",
                cs.time(taken)) + "</tr>"
        s += "</table>"
        if cnt != self.card.reps:
            s += '<div style="font-size: 12px;">' + _("""\
Note: Some of the history is missing. For more information, \
please see the browser documentation.""") + "</div>"
        return s

    # Menu helpers
    ######################################################################

    def selectedCards(self):
        return [self.model.cards[idx.row()] for idx in
                self.form.tableView.selectionModel().selectedRows()]

    def selectedNotes(self):
        return self.col.db.list("""
select distinct nid from cards
where id in %s""" % ids2str(
    [self.model.cards[idx.row()] for idx in
    self.form.tableView.selectionModel().selectedRows()]))

    def selectedNotesAsCards(self):
        return self.col.db.list(
            "select id from cards where nid in (%s)" %
            ",".join([str(s) for s in self.selectedNotes()]))

    def oneModelNotes(self):
        sf = self.selectedNotes()
        if not sf:
            return
        mods = self.col.db.scalar("""
select count(distinct mid) from notes
where id in %s""" % ids2str(sf))
        if mods > 1:
            showInfo(_("Please select cards from only one model."))
            return
        return sf

    def onHelp(self):
        openHelp("Browser")

    # Misc menu options
    ######################################################################

    def onChangeModel(self):
        return showInfo("not yet implemented")
        # given implicit card generation now, we need to fix model changing:
        # need to generate any unmapped cards
        nids = self.oneModelNotes()
        if nids:
            ChangeModel(self, nids)

    def cram(self):
        return showInfo("not yet implemented")
        self.close()
        self.mw.onCram(self.selectedCards())

    # Card deletion
    ######################################################################

    def deleteNotes(self):
        self.mw.checkpoint(_("Delete Notes"))
        self.model.beginReset()
        oldRow = self.form.tableView.selectionModel().currentIndex().row()
        self.col.remNotes(self.selectedNotes())
        self.onSearch(reset=False)
        if len(self.model.cards):
            new = min(oldRow, len(self.model.cards) - 1)
            self.model.focusedCard = self.model.cards[new]
        self.model.endReset()
        self.mw.requireReset()

    # Deck change
    ######################################################################

    def setDeck(self, initial=False):
        d = QDialog(self)
        d.setWindowModality(Qt.WindowModal)
        frm = aqt.forms.setgroup.Ui_Dialog()
        frm.setupUi(d)
        from aqt.tagedit import TagEdit
        te = TagEdit(d, type=1)
        frm.groupBox.layout().insertWidget(0, te)
        te.setCol(self.col)
        d.connect(d, SIGNAL("accepted()"), lambda: self._onSetDeck(frm, te))
        self.setTabOrder(frm.setCur, te)
        self.setTabOrder(te, frm.setInitial)
        if initial:
            frm.setInitial.setChecked(True)
        d.show()
        te.setFocus()

    def _onSetDeck(self, frm, te):
        self.model.beginReset()
        self.mw.checkpoint(_("Set Deck"))
        mod = intTime()
        if frm.setCur.isChecked():
            did = self.col.decks.id(unicode(te.text()))
            self.col.db.execute(
                "update cards set mod=?, did=? where id in " + ids2str(
                    self.selectedCards()), mod, did)
            if frm.setInitial.isChecked():
                self.col.db.execute(
                    "update notes set mod=?, did=? where id in " + ids2str(
                        self.selectedNotes()), mod, did)
        else:
            self.col.db.execute("""
update cards set mod=?, did=(select did from notes where id = cards.nid)
where id in %s""" % ids2str(self.selectedCards()), mod)
        self.onSearch(reset=False)
        self.mw.requireReset()
        self.model.endReset()

    # Tags
    ######################################################################

    def addTags(self, tags=None, label=None, prompt=None, func=None):
        if prompt is None:
            prompt = _("Enter tags to add:")
        if tags is None:
            (tags, r) = getTag(self, self.col, prompt)
        else:
            r = True
        if not r:
            return
        if func is None:
            func = self.col.tags.bulkAdd
        if label is None:
            label = _("Add Tags")
        if label:
            self.mw.checkpoint(label)
        func(self.selectedNotes(), tags)
        self.model.reset()
        self.mw.requireReset()

    def deleteTags(self, tags=None, label=None):
        if label is None:
            label = _("Delete Tags")
        self.addTags(tags, label, _("Enter tags to delete:"),
                     func=self.col.tags.bulkRem)

    # Suspending and marking
    ######################################################################

    def isSuspended(self):
        return not not (self.card and self.card.queue == -1)

    def onSuspend(self, sus=None):
        if sus is None:
            sus = not self.isSuspended()
        # focus lost hook may not have chance to fire
        self.editor.saveNow()
        c = self.selectedCards()
        if sus:
            self.col.sched.suspendCards(c)
        else:
            self.col.sched.unsuspendCards(c)
        self.model.reset()
        self.mw.requireReset()

    def isMarked(self):
        return not not (self.card and self.card.note().hasTag("Marked"))

    def onMark(self, mark=None):
        if mark is None:
            mark = not self.isMarked()
        if mark:
            self.addTags(tags="marked", label=False)
        else:
            self.deleteTags(tags="marked", label=False)

    # Repositioning
    ######################################################################

    def reposition(self):
        cids = self.selectedCards()
        cids = self.col.db.list(
            "select id from cards where type = 0 and id in " + ids2str(cids))
        if not cids:
            return showInfo(_("Only new cards can be repositioned."))
        d = QDialog(self)
        d.setWindowModality(Qt.WindowModal)
        frm = aqt.forms.reposition.Ui_Dialog()
        frm.setupUi(d)
        (pmin, pmax) = self.col.db.first(
            "select min(due), max(due) from cards where type=0")
        txt = _("Queue top: %d") % pmin
        txt += "\n" + _("Queue bottom: %d") % pmax
        frm.label.setText(txt)
        if not d.exec_():
            return
        self.model.beginReset()
        self.mw.checkpoint(_("Reposition"))
        self.col.sched.sortCards(
            cids, start=frm.start.value(), step=frm.step.value(),
            shuffle=frm.randomize.isChecked(), shift=frm.shift.isChecked())
        self.onSearch(reset=False)
        self.mw.requireReset()
        self.model.endReset()

    # Rescheduling
    ######################################################################

    def reschedule(self):
        d = QDialog(self)
        d.setWindowModality(Qt.WindowModal)
        frm = aqt.forms.reschedule.Ui_Dialog()
        frm.setupUi(d)
        if not d.exec_():
            return
        self.model.beginReset()
        self.mw.checkpoint(_("Reschedule"))
        if frm.asNew.isChecked():
            self.col.sched.forgetCards(self.selectedCards())
        else:
            self.col.sched.reschedCards(
                self.selectedCards(), frm.min.value(), frm.max.value())
        self.onSearch(reset=False)
        self.mw.requireReset()
        self.model.endReset()

    # Edit: selection
    ######################################################################

    def selectNotes(self):
        nids = self.selectedNotes()
        self.form.searchEdit.setText("nid:"+",".join([str(x) for x in nids]))
        # clear the selection so we don't waste energy preserving it
        tv = self.form.tableView
        tv.selectionModel().clear()
        self.onSearch()
        tv.selectAll()

    def invertSelection(self):
        sm = self.form.tableView.selectionModel()
        items = sm.selection()
        self.form.tableView.selectAll()
        sm.select(items, QItemSelectionModel.Deselect | QItemSelectionModel.Rows)

    # Edit: undo
    ######################################################################

    def setupHooks(self):
        addHook("undoState", self.onUndoState)
        addHook("reset", self.onReset)
        addHook("editTimer", self.refreshCurrentCard)
        addHook("editFocusLost", self.refreshCurrentCard)

    def teardownHooks(self):
        remHook("reset", self.onReset)
        remHook("editTimer", self.refreshCurrentCard)
        remHook("editFocusLost", self.refreshCurrentCard)
        remHook("undoState", self.onUndoState)

    def onUndoState(self, on):
        self.form.actionUndo.setEnabled(on)
        if on:
            self.form.actionUndo.setText(self.mw.form.actionUndo.text())

    # Options
    ######################################################################

    def onOptions(self):
        d = QDialog(self)
        frm = aqt.forms.browseropts.Ui_Dialog()
        frm.setupUi(d)
        frm.fontCombo.setCurrentFont(QFont(
            self.mw.pm.profile['editFontFamily']))
        frm.fontSize.setValue(self.mw.pm.profile['editFontSize'])
        frm.lineSize.setValue(self.mw.pm.profile['editLineSize'])
        frm.fullSearch.setChecked(self.mw.pm.profile['fullSearch'])
        if d.exec_():
            self.mw.pm.profile['editFontFamily'] = (
                unicode(frm.fontCombo.currentFont().family()))
            self.mw.pm.profile['editFontSize'] = (
                int(frm.fontSize.value()))
            self.mw.pm.profile['editLineSize'] = (
                int(frm.lineSize.value()))
            self.mw.pm.profile['fullSearch'] = frm.fullSearch.isChecked()
            self.updateFont()

    # Edit: replacing
    ######################################################################

    def onFindReplace(self):
        sf = self.selectedNotes()
        if not sf:
            return
        import anki.find
        fields = sorted(anki.find.fieldNames(self.col, downcase=False))
        d = QDialog(self)
        frm = aqt.forms.findreplace.Ui_Dialog()
        frm.setupUi(d)
        d.setWindowModality(Qt.WindowModal)
        frm.field.addItems([_("All Fields")] + fields)
        self.connect(frm.buttonBox, SIGNAL("helpRequested()"),
                     self.onFindReplaceHelp)
        if not d.exec_():
            return
        if frm.field.currentIndex() == 0:
            field = None
        else:
            field = fields[frm.field.currentIndex()-1]
        self.mw.checkpoint(_("Find and Replace"))
        self.mw.progress.start()
        self.model.beginReset()
        try:
            changed = self.col.findReplace(sf,
                                            unicode(frm.find.text()),
                                            unicode(frm.replace.text()),
                                            frm.re.isChecked(),
                                            field,
                                            frm.ignoreCase.isChecked())
        except sre_constants.error:
            ui.utils.showInfo(_("Invalid regular expression."),
                              parent=self)
            return
        else:
            self.onSearch()
            self.mw.requireReset()
        finally:
            self.model.endReset()
            self.mw.progress.finish()
        showInfo(ngettext(
            "%(a)d of %(b)d note updated",
            "%(a)d of %(b)d notes updated", len(sf)) % {
                'a': changed,
                'b': len(sf),
            })

    def onFindReplaceHelp(self):
        openHelp("Browser#FindReplace")

    # Edit: finding dupes
    ######################################################################

    def onFindDupes(self):
        return showInfo("not yet implemented")
        win = QDialog(self)
        aqt = ankiqt.forms.finddupes.Ui_Dialog()
        dialog.setupUi(win)
        restoreGeom(win, "findDupes")
        fields = sorted(self.card.note.model.fieldModels, key=attrgetter("name"))
        # per-model data
        data = self.col.db.all("""
select fm.id, m.name || '>' || fm.name from fieldmodels fm, models m
where fm.modelId = m.id""")
        data.sort(key=itemgetter(1))
        # all-model data
        data2 = self.col.db.all("""
select fm.id, fm.name from fieldmodels fm""")
        byName = {}
        for d in data2:
            if d[1] in byName:
                byName[d[1]].append(d[0])
            else:
                byName[d[1]] = [d[0]]
        names = byName.keys()
        names.sort()
        alldata = [(byName[n], n) for n in names] + data
        dialog.searchArea.addItems([d[1] for d in alldata])
        # links
        dialog.webView.page().setLinkDelegationPolicy(
            QWebPage.DelegateAllLinks)
        self.connect(dialog.webView,
                     SIGNAL("linkClicked(QUrl)"),
                     self.dupeLinkClicked)

        def onFin(code):
            saveGeom(win, "findDupes")
        self.connect(win, SIGNAL("finished(int)"), onFin)

        def onClick():
            idx = dialog.searchArea.currentIndex()
            data = alldata[idx]
            if isinstance(data[0], list):
                # all models
                fmids = data[0]
            else:
                # single model
                fmids = [data[0]]
            self.duplicatesReport(dialog.webView, fmids)

        self.connect(dialog.searchButton, SIGNAL("clicked()"),
                     onClick)
        win.show()

    def duplicatesReport(self, web, fmids):
        self.col.startProgress(2)
        self.col.updateProgress(_("Finding..."))
        res = self.col.findDuplicates(fmids)
        t = "<html><body>"
        t += _("Duplicate Groups: %d") % len(res)
        t += "<p><ol>"

        for group in res:
            t += '<li><a href="%s">%s</a>' % (
                "nid:" + ",".join(str(id) for id in group[1]),
                group[0])

        t += "</ol>"
        t += "</body></html>"
        web.setHtml(t)
        self.col.finishProgress()

    def dupeLinkClicked(self, link):
        self.form.searchEdit.setText(link.toString())
        self.onSearch()
        self.onNote()

    # Jumping
    ######################################################################

    def _moveCur(self, dir):
        if not self.model.cards:
            return
        self.editor.saveNow()
        tv = self.form.tableView
        idx = tv.moveCursor(dir, Qt.NoModifier)
        tv.selectionModel().clear()
        tv.setCurrentIndex(idx)

    def onPreviousCard(self):
        self._moveCur(QAbstractItemView.MoveUp)
        self.editor.web.setFocus()

    def onNextCard(self):
        self._moveCur(QAbstractItemView.MoveDown)
        self.editor.web.setFocus()

    def onFind(self):
        self.form.searchEdit.setFocus()
        self.form.searchEdit.selectAll()

    def onNote(self):
        self.editor.focus()

    def onTags(self):
        self.form.tree.setFocus()

    def onCardList(self):
        self.form.tableView.setFocus()
Exemplo n.º 51
0
 def setupToolbar(self):
     self.toolbarWeb = AnkiWebView()
     self.toolbarWeb.setFixedHeight(32)
     self.toolbar = BrowserToolbar(self.mw, self.toolbarWeb, self)
     self.form.verticalLayout_3.insertWidget(0, self.toolbarWeb)
     self.toolbar.draw()
Exemplo n.º 52
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self)
     self.editor = editor
     self.errtxt = _("An error occured while opening %s")
     self.strip = self.editor.mw.pm.profile['stripHTML']
Exemplo n.º 53
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self)
     self.editor = editor
     self.strip = self.editor.mw.pm.profile['stripHTML']
Exemplo n.º 54
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self, canFocus=True)
     self.editor = editor
     self.strip = self.editor.mw.pm.profile["stripHTML"]
Exemplo n.º 55
0
class VocabularyProfile(GenericProfile):
    name = "vocabulary"
    displayedName = "Vocabulary"
    descriptor = "VOCABULARY IN THIS TEXT (EXPORT)"
    languages = ["japanese","chinese","korean"]
    sortIndex = 1
    allowedTags = ['expression', 'term', 'source', 'kanji', 'hanja', 'reading', 'glossary', 'sentence','line','filename','summary','traditional','language','goo','defs','refs']

    def __init__(self,reader):
        GenericProfile.__init__(self,reader)
        self.history = []
        self.currentIndex = 0
        self.dockVocab = QtGui.QDockWidget(reader)
        self.dockVocab.setObjectName(fromUtf8("dockVocab"))
        self.dockWidgetContents = QtGui.QWidget()
        self.dockWidgetContents.setObjectName(fromUtf8("dockWidgetContents"))
        self.verticalLayout = QtGui.QVBoxLayout(self.dockWidgetContents)
        self.verticalLayout.setObjectName(fromUtf8("verticalLayout"))
        self.previousExpression = None
        self.textField = AnkiWebView()
        self.textField.setAcceptDrops(False)
        self.textField.setObjectName("textField")
        self.keyFilter = VocabKeyFilter()
        self.keyFilter.obj = self
        self.keyFilter.textField = self.textField
        self.textField.installEventFilter(self.keyFilter)
        self.verticalLayout.addWidget(self.textField)
        self.dockVocab.setWidget(self.dockWidgetContents)
        reader.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.dockVocab)
        self.dockVocab.visibilityChanged.connect(self.onVisibilityChanged)
        self.dockVocab.setWindowTitle(translate("MainWindowReader", "Vocabulary", None))
        self.textField.setLinkHandler(self.onAnchorClicked)

        # menu entries to toggle visibility of the vocabulary dock
        self.actionToggleVocab = QtGui.QAction(reader)
        self.actionToggleVocab.setCheckable(True)
        self.actionToggleVocab.setObjectName("actionToggleVocab")
        self.actionToggleVocab.setText("&Vocabulary")
        self.actionToggleVocab.setToolTip("Toggle vocabulary")
        reader.menuView.insertAction(reader.menuView.actions()[2],self.actionToggleVocab)
        QtCore.QObject.connect(self.actionToggleVocab, QtCore.SIGNAL("toggled(bool)"), self.dockVocab.setVisible)
        self.dockVocab.installEventFilter(self.reader.keyFilter)

    def updateSampleFromSelection(self):
        d = {
            "samplePosStart": 0,
            "contentSampleFlat": self.textField.selectedText(),
            "content": ""
        }
        self.onLookup(d,0,sentenceAndLine=False)

    def fixHtml(self,html,appendToHistory=True):
        if html.find(self.buildEmpty()) == -1 and appendToHistory:
            self.history.append((html,list(self.definitions),self.defBody))
        back = len(self.history)>1
        #self.currentIndex > 0
        #forward = self.currentIndex < len(self.history)-1
        if back:
            backHtml = "<a href='vocabulary_back:0'>&lt;&lt;Back</a>" if back else ""
            forwardHtml = ""
            #"<a href='vocabulary_forward:0'>Forward&gt;&gt;</a>" if forward else ""
            return u"<div>{1} {2}</div><br>{0}".format(html,backHtml,forwardHtml)
        else:
            return html

    def onVisibilityChanged(self,visible):
        self.actionToggleVocab.setChecked(self.dockVocab.isVisible())

    def onAnchorClicked(self, url):
        command, index = url.split(':')
        if command == "jisho":
            url = QtCore.QUrl(self.reader.preferences["linkToVocab"].format(index))
            QtGui.QDesktopServices().openUrl(url)
        elif command == "vocabulary_back":
            if len(self.history)>1:
                self.history.pop()
                html, definitions, body = self.history[-1]
                html = self.fixHtml(html,appendToHistory=False)
                self.textField.setHtml(html)
                self.definitions = definitions
                self.defBody = body
        elif command == "vocabulary_forward":
            self.textField.history().forward()
        else:
            if not index.startswith("void"):
                index = int(index)
                commands = command.split("_")
                profile = commands.pop(0)
                self.runCommand(commands,index)

    def onLookup(self,d,lengthMatched,sentenceAndLine=True):
        if self.dockVocab.isVisible():
            lengthMatched = self.reader.findTerm(d)
            if sentenceAndLine:
                sentence, sentenceStart = reader_util.findSentence(d['content'], d['samplePosStart'])
                line, lineStart  = reader_util.findLine(d['content'], d['samplePosStart'])
            else:
                sentence = line = ""
            for definition in self.definitions:
                definition['sentence'] = sentence
                definition['line'] = line
                definition['filename'] = self.reader.state.filename
            self.previousExpression = None
            self.reader.updateVocabDefs('vocabulary')
        return lengthMatched

    def onQuery(self,query):
        if self.dockVocab.isVisible():
            lengthMatched = self.reader.findTerm(query,wildcards=True)
            for definition in self.definitions:
                definition['sentence'] = ""
                definition['line'] = ""
                definition['filename'] = self.reader.state.filename
            self.previousExpression = None
            self.reader.updateVocabDefs('vocabulary')
        return lengthMatched

    def onShowDialogPreferences(self,dialog):
        dialog.checkHideTranslation = QtGui.QCheckBox(dialog.tabAnki)
        dialog.checkHideTranslation.setObjectName(fromUtf8("checkHideTranslation"))
        dialog.verticalLayout_2.addWidget(dialog.checkHideTranslation)
        dialog.checkHideTranslation.setText(translate("DialogPreferences", "Hide translation, when an online dictionary entry is present", None))
        GenericProfile.onShowDialogPreferences(self,dialog)

    def runCommand(self,cmds,index):
        if index >= len(self.definitions):
            return
        definition = self.definitions[index]
        if cmds[0] == "copy":
            if definition['reading']:
                result = u'{expression}\t{reading}\t{glossary}\n'.format(**definition)
            else:
                result = u'{expression}\t{glossary}\n'.format(**definition)
            if definition.get("defs"):
                text = self.reader.textContent.toPlainText() + "\n"
                self.reader.textContent.setPlainText(text +
                                                     definition.get("defs").replace(u"<br>",u"\n"))

            QtGui.QApplication.clipboard().setText(result)
        elif cmds[0] == "goo":
            prefix = "http://dictionary.goo.ne.jp"
            self.reader.link = prefix + "/srch/jn/" + definition['expression'] + "/m1u/"
            page = urllib2.urlopen(
              urllib2.Request(url=prefix + "/srch/jn/" + definition['expression'] + "/m1u/",
              headers={'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11'})).read()
            soup = BeautifulSoup.BeautifulSoup(page)
            if not soup.find("div","contents-wrap-b"):
                lis = soup.find("div",id="NR-main").find("div","contents-wrap-a-in search").find("ul","list-search-a").findAll("li")
                for li in lis:
                    hiragana = li.find("dt","search-ttl-a").contents[0].replace(u"\u2010",u"").replace(u"\u30fb",u"")
                    idx = hiragana.find(u"\u3010")
                    if idx>-1:
                        hiragana = hiragana[:idx]
                    self.reader.hiragana = [hiragana,definition['reading']]
                    self.reader.html = soup.contents[0]
                    if hiragana == definition['reading']:
                        a = li.find("a")
                        link = prefix + dict(a.attrs)["href"]
                        page2 = urllib2.urlopen(
                          urllib2.Request(url=link,
                          headers={'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11'})).read()
                        soup = BeautifulSoup.BeautifulSoup(page2)
            if soup.find("div","contents-wrap-b"):
                definition['goo'] = '\n'.join(map(unicode,soup.findAll("ol","list-data-b")))
                self.reader.preferences['onlineDicts']['goo'][definition['expression']+"["+(definition['reading'] or "")+"]"] = definition['goo']
                self.updateDefinitions()
        else:
            if len(cmds)>1 and cmds[1] == "reading":
                definition = definition.copy()
                definition['summary'] = definition['reading']
                definition['expression'] = definition['reading']
                definition['reading'] = unicode()
            if cmds[0] == "add":
                self.addFact(definition)
            elif cmds[0] == "overwrite":
                self.overwriteFact(definition)

    def markup(self, definition):
        if definition.get('reading'):
            summary = u'{expression}[{reading}]'.format(**definition)
        else:
            summary = u'{expression}'.format(**definition)

        return {
            'defs': definition.get("defs") or unicode(),
            'refs': definition.get("refs") or unicode(),
            'expression': definition['expression'],
            'hanja': definition.get('hanja') or unicode(),
            'reading': definition.get('reading') or unicode(),
            'glossary': definition.get('glossary') or unicode(),
            'gender': definition.get('gender') or unicode(),
            'language': definition.get('language') or unicode(),
            'sentence': definition.get('sentence') or unicode(),
            'traditional': definition.get('traditional') or unicode(),
            'line': definition.get('line') or unicode(),
            'filename': definition.get('filename') or unicode(),
            'goo': definition.get('goo') or unicode(),
            'term': definition.get('term') or unicode(),
            'source': definition.get('source') or unicode(),
            'summary': summary
        }

    def buildDefBody(self, definition, index, allowOverwrite):
        reading = unicode()
        if(definition.get('language') == 'Japanese' and (definition['expression']+"["+(definition['reading'] or "")+"]") in self.reader.preferences['onlineDicts']['goo']):
            definition['goo'] = self.reader.preferences['onlineDicts']['goo'][definition['expression']+"["+(definition['reading'] or "")+"]"]

        if definition.get('reading'):
            reading = u'<span class="reading">[{0}]<br>'.format(definition['reading'])
            if definition.get('tags') == u'traditional':
                reading += u' (trad.)'
            reading += '</span>'

        rules = unicode()
        if definition.get('rules'):
            rules = ' &lt; '.join(definition['rules'])
            rules = '<span class="rules">({0})<br></span>'.format(rules)

        gender = unicode()
        if definition.get('gender'):
            gender = '<span class="gender">{0}<br></span>'.format(definition['gender'])

        links = '<a href="vocabulary_copy:{0}"><img src="qrc:///img/img/icon_copy_definition.png" align="right"></a>'.format(index)
        markupExp = self.markup(definition)
        defReading = definition.copy()
        if defReading.get('reading'):
            defReading['expression'] = defReading['reading']
            del defReading['reading']
        markupReading = self.markup(defReading)
        if self.ankiIsFactValid('vocabulary', markupExp, index):
            links += u'<a href="vocabulary_add:{0}"><img src="qrc:///img/img/icon_add_expression.png" align="right"></a>'.format(index)
        else:
            if allowOverwrite:
                links += u'<a href="vocabulary_overwrite:{0}"><img src="qrc:///img/img/icon_overwrite_expression.png" align="right"></a>'.format(index)
        if markupReading is not None and definition.get('language') == 'Japanese':
            if self.ankiIsFactValid('vocabulary', markupReading, index):
                links += u'<a href="vocabulary_add_reading:{0}"><img src="qrc:///img/img/icon_add_reading.png" align="right"></a>'.format(index)
            elif markupExp is not None and markupReading['summary'] != markupExp['summary']:
                if allowOverwrite:
                    links += u'<a href="vocabulary_overwrite_reading:{0}"><img src="qrc:///img/img/icon_overwrite_reading.png" align="right"></a>'.format(index)

        def glossary(hide):
            if hide:
                return u"""<a onclick='document.getElementById("glossary{1}").style.display="block";this.style.display="none"' href="javascript:void(0);">[Show English]<br></a><span class="glossary" id="glossary{1}" style="display:none;">{0}<br></span>""".format(definition['glossary'],index)
            else:
                return u'<span class="glossary" id="glossary">{0}<br></span>'.format(definition['glossary'])
        foundOnlineDictEntry = False
        if markupExp["defs"] != "":
            dictionaryEntries = u"<span class='online'>"+ markupExp["defs"] + " " + markupExp["refs"] + "</span>"
            foundOnlineDictEntry = True
        else:
            dictionaryEntries = ""
        if(definition.get("goo")):
            dictionaryEntries += u"<br><span class='online'>" + definition["goo"] + "</span><br>"
            foundOnlineDictEntry = True
        elif(definition.get('language') == 'Japanese'):
            dictionaryEntries += u'<br><a href="vocabulary_goo:{0}">[Goo]</a><br>'.format(index)
        if(definition.get('language') == 'Japanese'):
            expression = u'<span class="expression"><a href="jisho:{0}">{0}</a></span>'.format(definition["expression"])
            reading = reading + '<br>'
        elif(definition.get('language') == 'German'):
            if self.previousExpression == definition['expression']:
                expression = ''
            else:
                expression = u'<span class="german">{0}</span><br>'.format(definition['expression'] + ' ' + gender)
                self.previousExpression = definition['expression']
        else:
            expression = u'<span class="expression">{0}</span>'.format(definition['expression'])
            reading = reading + '<br>'
        html = u"""
            <span class="links">{0}</span>
            {1}
            {2}
            {3}
            {4}
            {5}
            <br clear="all">""".format(links, expression, reading, glossary(foundOnlineDictEntry and self.reader.preferences['hideTranslation']), rules,dictionaryEntries)
        if (definition.get('language') != 'German'):
            html = u"<hr>" + html

        return html
Exemplo n.º 56
0
 def __init__(self, parent, editor):
     AnkiWebView.__init__(self)
     self.editor = editor
     self.errtxt = _("An error occured while opening %s")
     self.strip = True