split browser dialogs into separate files
This commit is contained in:
parent
0b8733032d
commit
b887032244
@ -7,8 +7,9 @@ import sys
|
|||||||
import aqt
|
import aqt
|
||||||
|
|
||||||
from .browser import Browser
|
from .browser import Browser
|
||||||
from .dialogs import CardInfoDialog, ChangeModel, FindAndReplaceDialog
|
|
||||||
from .previewer import BrowserPreviewer, MultiCardPreviewer, Previewer
|
# aliases for legacy pathnames
|
||||||
|
from .change_notetype import ChangeModel
|
||||||
from .sidebar import (
|
from .sidebar import (
|
||||||
SidebarItem,
|
SidebarItem,
|
||||||
SidebarItemType,
|
SidebarItemType,
|
||||||
@ -35,7 +36,6 @@ from .table import (
|
|||||||
Table,
|
Table,
|
||||||
)
|
)
|
||||||
|
|
||||||
# aliases for legacy pathnames
|
|
||||||
sys.modules["aqt.sidebar"] = sys.modules["aqt.browser.sidebar"]
|
sys.modules["aqt.sidebar"] = sys.modules["aqt.browser.sidebar"]
|
||||||
aqt.sidebar = sys.modules["aqt.browser.sidebar"] # type: ignore
|
aqt.sidebar = sys.modules["aqt.browser.sidebar"] # type: ignore
|
||||||
sys.modules["aqt.previewer"] = sys.modules["aqt.browser.previewer"]
|
sys.modules["aqt.previewer"] = sys.modules["aqt.browser.previewer"]
|
||||||
|
@ -13,15 +13,9 @@ from anki.consts import *
|
|||||||
from anki.errors import NotFoundError
|
from anki.errors import NotFoundError
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.notes import NoteId
|
from anki.notes import NoteId
|
||||||
from anki.stats import CardStats
|
|
||||||
from anki.tags import MARKED_TAG
|
from anki.tags import MARKED_TAG
|
||||||
from anki.utils import ids2str, isMac
|
from anki.utils import ids2str, isMac
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.browser.dialogs import CardInfoDialog, ChangeModel, FindAndReplaceDialog
|
|
||||||
from aqt.browser.previewer import BrowserPreviewer as PreviewDialog
|
|
||||||
from aqt.browser.previewer import Previewer
|
|
||||||
from aqt.browser.sidebar import SidebarTreeView
|
|
||||||
from aqt.browser.table import Table
|
|
||||||
from aqt.editor import Editor
|
from aqt.editor import Editor
|
||||||
from aqt.exporting import ExportDialog
|
from aqt.exporting import ExportDialog
|
||||||
from aqt.operations.card import set_card_deck, set_card_flag
|
from aqt.operations.card import set_card_deck, set_card_flag
|
||||||
@ -61,7 +55,14 @@ from aqt.utils import (
|
|||||||
skip_if_selection_is_empty,
|
skip_if_selection_is_empty,
|
||||||
tr,
|
tr,
|
||||||
)
|
)
|
||||||
from aqt.webview import AnkiWebView
|
|
||||||
|
from .card_info import CardInfoDialog
|
||||||
|
from .change_notetype import ChangeModel
|
||||||
|
from .find_and_replace import FindAndReplaceDialog
|
||||||
|
from .previewer import BrowserPreviewer as PreviewDialog
|
||||||
|
from .previewer import Previewer
|
||||||
|
from .sidebar import SidebarTreeView
|
||||||
|
from .table import Table
|
||||||
|
|
||||||
|
|
||||||
class Browser(QMainWindow):
|
class Browser(QMainWindow):
|
||||||
@ -478,34 +479,7 @@ class Browser(QMainWindow):
|
|||||||
if not self.card:
|
if not self.card:
|
||||||
return
|
return
|
||||||
|
|
||||||
info, cs = self._cardInfoData()
|
CardInfoDialog(parent=self, mw=self.mw, card=self.card)
|
||||||
reps = self._revlogData(cs)
|
|
||||||
|
|
||||||
card_info_dialog = CardInfoDialog(self)
|
|
||||||
l = QVBoxLayout()
|
|
||||||
l.setContentsMargins(0, 0, 0, 0)
|
|
||||||
w = AnkiWebView(title="browser card info")
|
|
||||||
l.addWidget(w)
|
|
||||||
w.stdHtml(info + "<p>" + reps, context=card_info_dialog)
|
|
||||||
bb = QDialogButtonBox(QDialogButtonBox.Close)
|
|
||||||
l.addWidget(bb)
|
|
||||||
qconnect(bb.rejected, card_info_dialog.reject)
|
|
||||||
card_info_dialog.setLayout(l)
|
|
||||||
card_info_dialog.setWindowModality(Qt.WindowModal)
|
|
||||||
card_info_dialog.resize(500, 400)
|
|
||||||
restoreGeom(card_info_dialog, "revlog")
|
|
||||||
card_info_dialog.show()
|
|
||||||
|
|
||||||
def _cardInfoData(self) -> Tuple[str, CardStats]:
|
|
||||||
cs = CardStats(self.col, self.card)
|
|
||||||
rep = cs.report(include_revlog=True)
|
|
||||||
return rep, cs
|
|
||||||
|
|
||||||
# legacy - revlog used to be generated here, and some add-ons
|
|
||||||
# wrapped this function
|
|
||||||
|
|
||||||
def _revlogData(self, cs: CardStats) -> str:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
# Menu helpers
|
# Menu helpers
|
||||||
######################################################################
|
######################################################################
|
||||||
|
39
qt/aqt/browser/card_info.py
Normal file
39
qt/aqt/browser/card_info.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import aqt
|
||||||
|
from anki.cards import Card
|
||||||
|
from anki.stats import CardStats
|
||||||
|
from aqt.qt import *
|
||||||
|
from aqt.utils import disable_help_button, qconnect, restoreGeom, saveGeom
|
||||||
|
from aqt.webview import AnkiWebView
|
||||||
|
|
||||||
|
|
||||||
|
class CardInfoDialog(QDialog):
|
||||||
|
silentlyClose = True
|
||||||
|
|
||||||
|
def __init__(self, parent: QWidget, mw: aqt.AnkiQt, card: Card) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
disable_help_button(self)
|
||||||
|
cs = CardStats(mw.col, card)
|
||||||
|
info = cs.report(include_revlog=True)
|
||||||
|
|
||||||
|
l = QVBoxLayout()
|
||||||
|
l.setContentsMargins(0, 0, 0, 0)
|
||||||
|
w = AnkiWebView(title="browser card info")
|
||||||
|
l.addWidget(w)
|
||||||
|
w.stdHtml(info + "<p>", context=self)
|
||||||
|
bb = QDialogButtonBox(QDialogButtonBox.Close)
|
||||||
|
l.addWidget(bb)
|
||||||
|
qconnect(bb.rejected, self.reject)
|
||||||
|
self.setLayout(l)
|
||||||
|
self.setWindowModality(Qt.WindowModal)
|
||||||
|
self.resize(500, 400)
|
||||||
|
restoreGeom(self, "revlog")
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def reject(self) -> None:
|
||||||
|
saveGeom(self, "revlog")
|
||||||
|
return QDialog.reject(self)
|
@ -9,9 +9,7 @@ import aqt
|
|||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.models import NotetypeDict
|
from anki.models import NotetypeDict
|
||||||
from anki.notes import NoteId
|
from anki.notes import NoteId
|
||||||
from aqt import AnkiQt, QWidget, gui_hooks
|
from aqt import QWidget, gui_hooks
|
||||||
from aqt.operations.note import find_and_replace
|
|
||||||
from aqt.operations.tag import find_and_replace_tag
|
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
HelpPage,
|
HelpPage,
|
||||||
@ -19,13 +17,7 @@ from aqt.utils import (
|
|||||||
disable_help_button,
|
disable_help_button,
|
||||||
openHelp,
|
openHelp,
|
||||||
qconnect,
|
qconnect,
|
||||||
restore_combo_history,
|
|
||||||
restore_combo_index_for_session,
|
|
||||||
restore_is_checked,
|
|
||||||
restoreGeom,
|
restoreGeom,
|
||||||
save_combo_history,
|
|
||||||
save_combo_index_for_session,
|
|
||||||
save_is_checked,
|
|
||||||
saveGeom,
|
saveGeom,
|
||||||
tr,
|
tr,
|
||||||
)
|
)
|
||||||
@ -213,116 +205,3 @@ class ChangeModel(QDialog):
|
|||||||
|
|
||||||
def onHelp(self) -> None:
|
def onHelp(self) -> None:
|
||||||
openHelp(HelpPage.BROWSING_OTHER_MENU_ITEMS)
|
openHelp(HelpPage.BROWSING_OTHER_MENU_ITEMS)
|
||||||
|
|
||||||
|
|
||||||
class CardInfoDialog(QDialog):
|
|
||||||
silentlyClose = True
|
|
||||||
|
|
||||||
def __init__(self, browser: aqt.browser.Browser) -> None:
|
|
||||||
super().__init__(browser)
|
|
||||||
self.browser = browser
|
|
||||||
disable_help_button(self)
|
|
||||||
|
|
||||||
def reject(self) -> None:
|
|
||||||
saveGeom(self, "revlog")
|
|
||||||
return QDialog.reject(self)
|
|
||||||
|
|
||||||
|
|
||||||
class FindAndReplaceDialog(QDialog):
|
|
||||||
COMBO_NAME = "BrowserFindAndReplace"
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, parent: QWidget, *, mw: AnkiQt, note_ids: Sequence[NoteId]
|
|
||||||
) -> None:
|
|
||||||
super().__init__(parent)
|
|
||||||
self.mw = mw
|
|
||||||
self.note_ids = note_ids
|
|
||||||
self.field_names: List[str] = []
|
|
||||||
|
|
||||||
# fetch field names and then show
|
|
||||||
mw.query_op(
|
|
||||||
lambda: mw.col.field_names_for_note_ids(note_ids),
|
|
||||||
success=self._show,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _show(self, field_names: Sequence[str]) -> None:
|
|
||||||
# add "all fields" and "tags" to the top of the list
|
|
||||||
self.field_names = [
|
|
||||||
tr.browsing_all_fields(),
|
|
||||||
tr.editing_tags(),
|
|
||||||
] + list(field_names)
|
|
||||||
|
|
||||||
disable_help_button(self)
|
|
||||||
self.form = aqt.forms.findreplace.Ui_Dialog()
|
|
||||||
self.form.setupUi(self)
|
|
||||||
self.setWindowModality(Qt.WindowModal)
|
|
||||||
|
|
||||||
self._find_history = restore_combo_history(
|
|
||||||
self.form.find, self.COMBO_NAME + "Find"
|
|
||||||
)
|
|
||||||
self.form.find.completer().setCaseSensitivity(Qt.CaseSensitive)
|
|
||||||
self._replace_history = restore_combo_history(
|
|
||||||
self.form.replace, self.COMBO_NAME + "Replace"
|
|
||||||
)
|
|
||||||
self.form.replace.completer().setCaseSensitivity(Qt.CaseSensitive)
|
|
||||||
|
|
||||||
restore_is_checked(self.form.re, self.COMBO_NAME + "Regex")
|
|
||||||
restore_is_checked(self.form.ignoreCase, self.COMBO_NAME + "ignoreCase")
|
|
||||||
|
|
||||||
self.form.field.addItems(self.field_names)
|
|
||||||
restore_combo_index_for_session(
|
|
||||||
self.form.field, self.field_names, self.COMBO_NAME + "Field"
|
|
||||||
)
|
|
||||||
|
|
||||||
qconnect(self.form.buttonBox.helpRequested, self.show_help)
|
|
||||||
|
|
||||||
restoreGeom(self, "findreplace")
|
|
||||||
self.show()
|
|
||||||
self.form.find.setFocus()
|
|
||||||
|
|
||||||
def accept(self) -> None:
|
|
||||||
saveGeom(self, "findreplace")
|
|
||||||
save_combo_index_for_session(self.form.field, self.COMBO_NAME + "Field")
|
|
||||||
|
|
||||||
search = save_combo_history(
|
|
||||||
self.form.find, self._find_history, self.COMBO_NAME + "Find"
|
|
||||||
)
|
|
||||||
replace = save_combo_history(
|
|
||||||
self.form.replace, self._replace_history, self.COMBO_NAME + "Replace"
|
|
||||||
)
|
|
||||||
regex = self.form.re.isChecked()
|
|
||||||
match_case = not self.form.ignoreCase.isChecked()
|
|
||||||
save_is_checked(self.form.re, self.COMBO_NAME + "Regex")
|
|
||||||
save_is_checked(self.form.ignoreCase, self.COMBO_NAME + "ignoreCase")
|
|
||||||
|
|
||||||
# tags?
|
|
||||||
if self.form.field.currentIndex() == 1:
|
|
||||||
find_and_replace_tag(
|
|
||||||
parent=self.parentWidget(),
|
|
||||||
note_ids=self.note_ids,
|
|
||||||
search=search,
|
|
||||||
replacement=replace,
|
|
||||||
regex=regex,
|
|
||||||
match_case=match_case,
|
|
||||||
).run_in_background()
|
|
||||||
else:
|
|
||||||
# fields
|
|
||||||
if self.form.field.currentIndex() == 0:
|
|
||||||
field = None
|
|
||||||
else:
|
|
||||||
field = self.field_names[self.form.field.currentIndex() - 2]
|
|
||||||
|
|
||||||
find_and_replace(
|
|
||||||
parent=self.parentWidget(),
|
|
||||||
note_ids=self.note_ids,
|
|
||||||
search=search,
|
|
||||||
replacement=replace,
|
|
||||||
regex=regex,
|
|
||||||
field_name=field,
|
|
||||||
match_case=match_case,
|
|
||||||
).run_in_background()
|
|
||||||
|
|
||||||
super().accept()
|
|
||||||
|
|
||||||
def show_help(self) -> None:
|
|
||||||
openHelp(HelpPage.BROWSING_FIND_AND_REPLACE)
|
|
128
qt/aqt/browser/find_and_replace.py
Normal file
128
qt/aqt/browser/find_and_replace.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import List, Sequence
|
||||||
|
|
||||||
|
import aqt
|
||||||
|
from anki.notes import NoteId
|
||||||
|
from aqt import AnkiQt
|
||||||
|
from aqt.operations.note import find_and_replace
|
||||||
|
from aqt.operations.tag import find_and_replace_tag
|
||||||
|
from aqt.qt import *
|
||||||
|
from aqt.utils import (
|
||||||
|
HelpPage,
|
||||||
|
disable_help_button,
|
||||||
|
openHelp,
|
||||||
|
qconnect,
|
||||||
|
restore_combo_history,
|
||||||
|
restore_combo_index_for_session,
|
||||||
|
restore_is_checked,
|
||||||
|
restoreGeom,
|
||||||
|
save_combo_history,
|
||||||
|
save_combo_index_for_session,
|
||||||
|
save_is_checked,
|
||||||
|
saveGeom,
|
||||||
|
tr,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FindAndReplaceDialog(QDialog):
|
||||||
|
COMBO_NAME = "BrowserFindAndReplace"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, parent: QWidget, *, mw: AnkiQt, note_ids: Sequence[NoteId]
|
||||||
|
) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.mw = mw
|
||||||
|
self.note_ids = note_ids
|
||||||
|
self.field_names: List[str] = []
|
||||||
|
|
||||||
|
# fetch field names and then show
|
||||||
|
mw.query_op(
|
||||||
|
lambda: mw.col.field_names_for_note_ids(note_ids),
|
||||||
|
success=self._show,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _show(self, field_names: Sequence[str]) -> None:
|
||||||
|
# add "all fields" and "tags" to the top of the list
|
||||||
|
self.field_names = [
|
||||||
|
tr.browsing_all_fields(),
|
||||||
|
tr.editing_tags(),
|
||||||
|
] + list(field_names)
|
||||||
|
|
||||||
|
disable_help_button(self)
|
||||||
|
self.form = aqt.forms.findreplace.Ui_Dialog()
|
||||||
|
self.form.setupUi(self)
|
||||||
|
self.setWindowModality(Qt.WindowModal)
|
||||||
|
|
||||||
|
self._find_history = restore_combo_history(
|
||||||
|
self.form.find, self.COMBO_NAME + "Find"
|
||||||
|
)
|
||||||
|
self.form.find.completer().setCaseSensitivity(Qt.CaseSensitive)
|
||||||
|
self._replace_history = restore_combo_history(
|
||||||
|
self.form.replace, self.COMBO_NAME + "Replace"
|
||||||
|
)
|
||||||
|
self.form.replace.completer().setCaseSensitivity(Qt.CaseSensitive)
|
||||||
|
|
||||||
|
restore_is_checked(self.form.re, self.COMBO_NAME + "Regex")
|
||||||
|
restore_is_checked(self.form.ignoreCase, self.COMBO_NAME + "ignoreCase")
|
||||||
|
|
||||||
|
self.form.field.addItems(self.field_names)
|
||||||
|
restore_combo_index_for_session(
|
||||||
|
self.form.field, self.field_names, self.COMBO_NAME + "Field"
|
||||||
|
)
|
||||||
|
|
||||||
|
qconnect(self.form.buttonBox.helpRequested, self.show_help)
|
||||||
|
|
||||||
|
restoreGeom(self, "findreplace")
|
||||||
|
self.show()
|
||||||
|
self.form.find.setFocus()
|
||||||
|
|
||||||
|
def accept(self) -> None:
|
||||||
|
saveGeom(self, "findreplace")
|
||||||
|
save_combo_index_for_session(self.form.field, self.COMBO_NAME + "Field")
|
||||||
|
|
||||||
|
search = save_combo_history(
|
||||||
|
self.form.find, self._find_history, self.COMBO_NAME + "Find"
|
||||||
|
)
|
||||||
|
replace = save_combo_history(
|
||||||
|
self.form.replace, self._replace_history, self.COMBO_NAME + "Replace"
|
||||||
|
)
|
||||||
|
regex = self.form.re.isChecked()
|
||||||
|
match_case = not self.form.ignoreCase.isChecked()
|
||||||
|
save_is_checked(self.form.re, self.COMBO_NAME + "Regex")
|
||||||
|
save_is_checked(self.form.ignoreCase, self.COMBO_NAME + "ignoreCase")
|
||||||
|
|
||||||
|
# tags?
|
||||||
|
if self.form.field.currentIndex() == 1:
|
||||||
|
find_and_replace_tag(
|
||||||
|
parent=self.parentWidget(),
|
||||||
|
note_ids=self.note_ids,
|
||||||
|
search=search,
|
||||||
|
replacement=replace,
|
||||||
|
regex=regex,
|
||||||
|
match_case=match_case,
|
||||||
|
).run_in_background()
|
||||||
|
else:
|
||||||
|
# fields
|
||||||
|
if self.form.field.currentIndex() == 0:
|
||||||
|
field = None
|
||||||
|
else:
|
||||||
|
field = self.field_names[self.form.field.currentIndex() - 2]
|
||||||
|
|
||||||
|
find_and_replace(
|
||||||
|
parent=self.parentWidget(),
|
||||||
|
note_ids=self.note_ids,
|
||||||
|
search=search,
|
||||||
|
replacement=replace,
|
||||||
|
regex=regex,
|
||||||
|
field_name=field,
|
||||||
|
match_case=match_case,
|
||||||
|
).run_in_background()
|
||||||
|
|
||||||
|
super().accept()
|
||||||
|
|
||||||
|
def show_help(self) -> None:
|
||||||
|
openHelp(HelpPage.BROWSING_FIND_AND_REPLACE)
|
Loading…
Reference in New Issue
Block a user