2021-05-08 07:08:45 +02:00
|
|
|
# Copyright: Ankitects Pty Ltd and contributors
|
|
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-10-03 10:59:42 +02:00
|
|
|
from typing import Sequence
|
2021-05-08 07:08:45 +02:00
|
|
|
|
|
|
|
import aqt
|
2022-02-13 04:40:47 +01:00
|
|
|
import aqt.forms
|
|
|
|
import aqt.operations
|
2021-05-08 07:08:45 +02:00
|
|
|
from anki.notes import NoteId
|
|
|
|
from aqt import AnkiQt
|
2021-05-08 08:20:10 +02:00
|
|
|
from aqt.operations import QueryOp
|
2021-05-08 07:08:45 +02:00
|
|
|
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,
|
2021-07-13 16:33:45 +02:00
|
|
|
tooltip,
|
2021-05-08 07:08:45 +02:00
|
|
|
tr,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class FindAndReplaceDialog(QDialog):
|
|
|
|
COMBO_NAME = "BrowserFindAndReplace"
|
|
|
|
|
|
|
|
def __init__(
|
2021-07-13 16:33:45 +02:00
|
|
|
self,
|
|
|
|
parent: QWidget,
|
|
|
|
*,
|
|
|
|
mw: AnkiQt,
|
|
|
|
note_ids: Sequence[NoteId],
|
2021-10-03 10:59:42 +02:00
|
|
|
field: str | None = None,
|
2021-05-08 07:08:45 +02:00
|
|
|
) -> None:
|
2021-07-13 16:33:45 +02:00
|
|
|
"""
|
|
|
|
If 'field' is passed, only this is added to the field selector.
|
|
|
|
Otherwise, the fields belonging to the 'note_ids' are added.
|
|
|
|
"""
|
2021-05-08 07:08:45 +02:00
|
|
|
super().__init__(parent)
|
|
|
|
self.mw = mw
|
|
|
|
self.note_ids = note_ids
|
2021-10-03 10:59:42 +02:00
|
|
|
self.field_names: list[str] = []
|
2021-07-13 16:33:45 +02:00
|
|
|
self._field = field
|
|
|
|
|
|
|
|
if field:
|
|
|
|
self._show([field])
|
|
|
|
elif note_ids:
|
|
|
|
# fetch field names and then show
|
|
|
|
QueryOp(
|
|
|
|
parent=mw,
|
|
|
|
op=lambda col: col.field_names_for_note_ids(note_ids),
|
|
|
|
success=self._show,
|
|
|
|
).run_in_background()
|
|
|
|
else:
|
|
|
|
self._show([])
|
2021-05-08 07:08:45 +02:00
|
|
|
|
|
|
|
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)
|
2021-10-05 05:53:01 +02:00
|
|
|
self.setWindowModality(Qt.WindowModality.WindowModal)
|
2021-05-08 07:08:45 +02:00
|
|
|
|
|
|
|
self._find_history = restore_combo_history(
|
|
|
|
self.form.find, self.COMBO_NAME + "Find"
|
|
|
|
)
|
2021-10-05 05:53:01 +02:00
|
|
|
self.form.find.completer().setCaseSensitivity(Qt.CaseSensitivity.CaseSensitive)
|
2021-05-08 07:08:45 +02:00
|
|
|
self._replace_history = restore_combo_history(
|
|
|
|
self.form.replace, self.COMBO_NAME + "Replace"
|
|
|
|
)
|
2021-10-05 05:53:01 +02:00
|
|
|
self.form.replace.completer().setCaseSensitivity(
|
|
|
|
Qt.CaseSensitivity.CaseSensitive
|
|
|
|
)
|
2021-05-08 07:08:45 +02:00
|
|
|
|
2021-07-13 16:33:45 +02:00
|
|
|
if not self.note_ids:
|
|
|
|
# no selected notes to affect
|
|
|
|
self.form.selected_notes.setChecked(False)
|
|
|
|
self.form.selected_notes.setEnabled(False)
|
|
|
|
elif self._field:
|
|
|
|
self.form.selected_notes.setChecked(False)
|
|
|
|
|
2021-05-08 07:08:45 +02:00
|
|
|
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)
|
2021-07-13 16:33:45 +02:00
|
|
|
if self._field:
|
|
|
|
self.form.field.setCurrentIndex(self.field_names.index(self._field))
|
|
|
|
else:
|
|
|
|
restore_combo_index_for_session(
|
|
|
|
self.form.field, self.field_names, self.COMBO_NAME + "Field"
|
|
|
|
)
|
2021-05-08 07:08:45 +02:00
|
|
|
|
|
|
|
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")
|
|
|
|
|
2021-07-13 16:33:45 +02:00
|
|
|
if not self.form.selected_notes.isChecked():
|
|
|
|
# an empty list means *all* notes
|
|
|
|
self.note_ids = []
|
|
|
|
|
2021-05-08 07:08:45 +02:00
|
|
|
# tags?
|
|
|
|
if self.form.field.currentIndex() == 1:
|
2021-07-13 16:33:45 +02:00
|
|
|
op = find_and_replace_tag(
|
2021-05-08 07:08:45 +02:00
|
|
|
parent=self.parentWidget(),
|
|
|
|
note_ids=self.note_ids,
|
|
|
|
search=search,
|
|
|
|
replacement=replace,
|
|
|
|
regex=regex,
|
|
|
|
match_case=match_case,
|
2021-07-13 16:33:45 +02:00
|
|
|
)
|
2021-05-08 07:08:45 +02:00
|
|
|
else:
|
|
|
|
# fields
|
|
|
|
if self.form.field.currentIndex() == 0:
|
|
|
|
field = None
|
|
|
|
else:
|
2021-05-22 02:12:14 +02:00
|
|
|
field = self.field_names[self.form.field.currentIndex()]
|
2021-05-08 07:08:45 +02:00
|
|
|
|
2021-07-13 16:33:45 +02:00
|
|
|
op = find_and_replace(
|
2021-05-08 07:08:45 +02:00
|
|
|
parent=self.parentWidget(),
|
|
|
|
note_ids=self.note_ids,
|
|
|
|
search=search,
|
|
|
|
replacement=replace,
|
|
|
|
regex=regex,
|
|
|
|
field_name=field,
|
|
|
|
match_case=match_case,
|
2021-07-13 16:33:45 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
if not self.note_ids:
|
|
|
|
op.success(
|
|
|
|
lambda out: tooltip(
|
|
|
|
tr.browsing_notes_updated(count=out.count),
|
|
|
|
parent=self.parentWidget(),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
op.run_in_background()
|
2021-05-08 07:08:45 +02:00
|
|
|
|
|
|
|
super().accept()
|
|
|
|
|
|
|
|
def show_help(self) -> None:
|
|
|
|
openHelp(HelpPage.BROWSING_FIND_AND_REPLACE)
|