add booleans for various screens to OpChanges

The backend knows exactly which op has executed, and it saves us having
to re-implement this logic on each client.

Fixes the browser table refreshing when toggling decks.
This commit is contained in:
Damien Elmes 2021-04-05 14:28:56 +10:00
parent f6ec5928ae
commit a18bb2af12
12 changed files with 67 additions and 34 deletions

View file

@ -133,7 +133,7 @@ class Browser(QMainWindow):
self.table.op_executed(changes, meta, focused)
self.sidebar.op_executed(changes, meta, focused)
if changes.note or changes.notetype:
if meta.handled_by is not self.editor:
if meta.handler is not self.editor:
# fixme: this will leave the splitter shown, but with no current
# note being edited
note = self.editor.note

View file

@ -32,21 +32,17 @@ class EditCurrent(QDialog):
self.show()
def on_operation_did_execute(self, changes: OpChanges, meta: OpMeta) -> None:
if not (changes.note or changes.notetype):
return
if meta.handled_by is self.editor:
return
if changes.editor and meta.handler is not self.editor:
# reload note
note = self.editor.note
try:
note.load()
except NotFoundError:
# note's been deleted
self.cleanup_and_close()
return
# reload note
note = self.editor.note
try:
note.load()
except NotFoundError:
# note's been deleted
self.cleanup_and_close()
return
self.editor.set_note(note)
self.editor.set_note(note)
def cleanup_and_close(self) -> None:
gui_hooks.operation_did_execute.remove(self.on_operation_did_execute)

View file

@ -100,7 +100,7 @@ class Editor:
redrawing.
The editor will cause that hook to be fired when it saves changes. To avoid
an unwanted refresh, the parent widget should check if meta.handled_by
an unwanted refresh, the parent widget should check if meta.handler
corresponds to this editor instance, and ignore the change if it does.
"""
@ -558,7 +558,7 @@ class Editor:
def _save_current_note(self) -> None:
"Call after note is updated with data from webview."
update_note(mw=self.mw, note=self.note, handled_by=self)
update_note(mw=self.mw, note=self.note, handler=self)
def fonts(self) -> List[Tuple[str, int, bool]]:
return [

View file

@ -9,8 +9,8 @@ from typing import Optional
class OpMeta:
"""Metadata associated with an operation.
The `handled_by` field can be used by screens to ignore change
The `handler` field can be used by screens to ignore change
events they initiated themselves, if they have already made
the required changes."""
handled_by: Optional[object] = None
handler: Optional[object] = None

View file

@ -77,11 +77,11 @@ def set_deck_collapsed(
deck_id: DeckId,
collapsed: bool,
scope: DeckCollapseScope.V,
handled_by: Optional[object] = None,
handler: Optional[object] = None,
) -> None:
mw.perform_op(
lambda: mw.col.decks.set_collapsed(
deck_id=deck_id, collapsed=collapsed, scope=scope
),
meta=OpMeta(handled_by=handled_by),
meta=OpMeta(handler=handler),
)

View file

@ -22,10 +22,10 @@ def add_note(
mw.perform_op(lambda: mw.col.add_note(note, target_deck_id), success=success)
def update_note(*, mw: AnkiQt, note: Note, handled_by: Optional[object]) -> None:
def update_note(*, mw: AnkiQt, note: Note, handler: Optional[object]) -> None:
mw.perform_op(
lambda: mw.col.update_note(note),
meta=OpMeta(handled_by=handled_by),
meta=OpMeta(handler=handler),
)

View file

@ -420,11 +420,8 @@ class SidebarTreeView(QTreeView):
# Refreshing
###########################
def op_executed(self, op: OpChanges, meta: OpMeta, focused: bool) -> None:
if meta.handled_by is self:
return
if op.tag or op.notetype or op.deck:
def op_executed(self, changes: OpChanges, meta: OpMeta, focused: bool) -> None:
if changes.browser_sidebar and not meta.handler is self:
self._refresh_needed = True
if focused:
self.refresh_if_needed()
@ -984,7 +981,7 @@ class SidebarTreeView(QTreeView):
deck_id=DeckId(node.deck_id),
collapsed=not expanded,
scope=DeckCollapseScope.BROWSER,
handled_by=self,
handler=self,
)
for node in nodes:

View file

@ -180,9 +180,8 @@ class Table:
def redraw_cells(self) -> None:
self._model.redraw_cells()
def op_executed(self, op: OpChanges, meta: OpMeta, focused: bool) -> None:
print("op executed")
if op.card or op.note or op.deck or op.notetype:
def op_executed(self, changes: OpChanges, meta: OpMeta, focused: bool) -> None:
if changes.browser_table:
self._model.empty_cache()
if focused:
self.redraw_cells()

View file

@ -1513,6 +1513,11 @@ message OpChanges {
bool tag = 5;
bool notetype = 6;
bool preference = 7;
bool browser_table = 8;
bool browser_sidebar = 9;
bool editor = 10;
bool study_queues = 11;
}
message UndoStatus {

View file

@ -31,6 +31,10 @@ impl From<OpChanges> for pb::OpChanges {
tag: c.changes.tag,
notetype: c.changes.notetype,
preference: c.changes.preference,
browser_table: c.requires_browser_table_redraw(),
browser_sidebar: c.requires_browser_sidebar_redraw(),
editor: c.requires_editor_redraw(),
study_queues: c.requires_study_queue_rebuild(),
}
}
}

View file

@ -105,3 +105,36 @@ impl<T> OpOutput<T> {
}
}
}
impl OpChanges {
// These routines should return true even if the GUI may have
// special handling for an action, since we need to do the right
// thing when undoing, and if multiple windows of the same type are
// open. For example, while toggling the expand/collapse state
// in the sidebar will not normally trigger a full sidebar refresh,
// requires_browser_sidebar_redraw() should still return true.
pub fn requires_browser_table_redraw(&self) -> bool {
let c = &self.changes;
c.card
|| c.notetype
|| (c.note && self.op != Op::AddNote)
|| (c.deck && self.op != Op::ExpandCollapse)
}
pub fn requires_browser_sidebar_redraw(&self) -> bool {
let c = &self.changes;
c.tag || c.deck || c.notetype
}
pub fn requires_editor_redraw(&self) -> bool {
let c = &self.changes;
c.note || c.notetype
}
pub fn requires_study_queue_rebuild(&self) -> bool {
let c = &self.changes;
!matches!(self.op, Op::AnswerCard | Op::ExpandCollapse)
&& (c.card || c.deck || c.preference)
}
}

View file

@ -140,8 +140,7 @@ impl Collection {
}
pub(crate) fn maybe_clear_study_queues_after_op(&mut self, op: OpChanges) {
if op.op != Op::AnswerCard && (op.changes.card || op.changes.deck || op.changes.preference)
{
if op.requires_study_queue_rebuild() {
self.state.card_queues = None;
}
}