mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
various redraw fixes
- need to drop cardObjs cache when updating cells - stop listening on editor_did_* hooks. unfocus_field and typing_timer are covered by operation_did_execute on note save already, and the user potentially has editors open in other windows as well - distinguish between card queue refresh and note text redraw in review screen again - update preview window when note updated - defer setUpdatesEnabled(True) until we receive focus again, as it causes cells to redraw. We might want to use our own flag to prevent updating in the model instead of using Qt for this
This commit is contained in:
parent
3f87f7bf5c
commit
017005a4f8
3 changed files with 43 additions and 43 deletions
|
@ -17,7 +17,6 @@ from anki.consts import *
|
|||
from anki.errors import InvalidInput, NotFoundError
|
||||
from anki.lang import without_unicode_isolation
|
||||
from anki.models import NoteType
|
||||
from anki.notes import Note
|
||||
from anki.stats import CardStats
|
||||
from anki.utils import htmlToTextLine, ids2str, isMac, isWin
|
||||
from aqt import AnkiQt, colors, gui_hooks
|
||||
|
@ -112,15 +111,6 @@ class DataModel(QAbstractTableModel):
|
|||
self.cardObjs[id] = card
|
||||
return self.cardObjs[id]
|
||||
|
||||
def refreshNote(self, note: Note) -> None:
|
||||
refresh = False
|
||||
for c in note.cards():
|
||||
if c.id in self.cardObjs:
|
||||
del self.cardObjs[c.id]
|
||||
refresh = True
|
||||
if refresh:
|
||||
self.layoutChanged.emit() # type: ignore
|
||||
|
||||
# Model interface
|
||||
######################################################################
|
||||
|
||||
|
@ -214,8 +204,9 @@ class DataModel(QAbstractTableModel):
|
|||
if not self.cards:
|
||||
return
|
||||
top_left = self.index(0, 0)
|
||||
bottom_right = self.index(len(self.cards)-1, len(self.activeCols)-1)
|
||||
self.dataChanged.emit(top_left, bottom_right)
|
||||
bottom_right = self.index(len(self.cards) - 1, len(self.activeCols) - 1)
|
||||
self.cardObjs = {}
|
||||
self.dataChanged.emit(top_left, bottom_right) # type: ignore
|
||||
|
||||
def reset(self) -> None:
|
||||
self.beginReset()
|
||||
|
@ -513,16 +504,22 @@ class Browser(QMainWindow):
|
|||
self.setUpdatesEnabled(False)
|
||||
|
||||
def on_operation_did_execute(self, changes: OpChanges) -> None:
|
||||
self.setUpdatesEnabled(True)
|
||||
self.model.op_executed(changes, current_top_level_widget() == self)
|
||||
if (changes.note or changes.notetype) and not self.editor.is_updating_note():
|
||||
note = self.editor.note
|
||||
if note:
|
||||
note.load()
|
||||
self.editor.set_note(note)
|
||||
focused = current_top_level_widget() == self
|
||||
if focused:
|
||||
self.setUpdatesEnabled(True)
|
||||
self.model.op_executed(changes, focused)
|
||||
if changes.note or changes.notetype:
|
||||
if not self.editor.is_updating_note():
|
||||
note = self.editor.note
|
||||
if note:
|
||||
note.load()
|
||||
self.editor.set_note(note)
|
||||
|
||||
self._renderPreview()
|
||||
|
||||
def on_focus_change(self, new: Optional[QWidget], old: Optional[QWidget]) -> None:
|
||||
if current_top_level_widget() == self:
|
||||
self.setUpdatesEnabled(True)
|
||||
self.model.refresh_if_needed()
|
||||
|
||||
def setupMenus(self) -> None:
|
||||
|
@ -860,13 +857,6 @@ QTableView {{ gridline-color: {grid} }}
|
|||
self._updateFlagsMenu()
|
||||
gui_hooks.browser_did_change_row(self)
|
||||
|
||||
def refreshCurrentCard(self, note: Note) -> None:
|
||||
self.model.refreshNote(note)
|
||||
self._renderPreview()
|
||||
|
||||
def onLoadNote(self, editor: Editor) -> None:
|
||||
self.refreshCurrentCard(editor.note)
|
||||
|
||||
def currentRow(self) -> int:
|
||||
idx = self.form.tableView.selectionModel().currentIndex()
|
||||
return idx.row()
|
||||
|
@ -1452,9 +1442,6 @@ where id in %s"""
|
|||
|
||||
def setupHooks(self) -> None:
|
||||
gui_hooks.undo_state_did_change.append(self.onUndoState)
|
||||
gui_hooks.editor_did_fire_typing_timer.append(self.refreshCurrentCard)
|
||||
gui_hooks.editor_did_load_note.append(self.onLoadNote)
|
||||
gui_hooks.editor_did_unfocus_field.append(self.on_unfocus_field)
|
||||
gui_hooks.sidebar_should_refresh_decks.append(self.on_item_added)
|
||||
gui_hooks.sidebar_should_refresh_notetypes.append(self.on_item_added)
|
||||
gui_hooks.operation_will_execute.append(self.on_operation_will_execute)
|
||||
|
@ -1463,18 +1450,12 @@ where id in %s"""
|
|||
|
||||
def teardownHooks(self) -> None:
|
||||
gui_hooks.undo_state_did_change.remove(self.onUndoState)
|
||||
gui_hooks.editor_did_fire_typing_timer.remove(self.refreshCurrentCard)
|
||||
gui_hooks.editor_did_load_note.remove(self.onLoadNote)
|
||||
gui_hooks.editor_did_unfocus_field.remove(self.on_unfocus_field)
|
||||
gui_hooks.sidebar_should_refresh_decks.remove(self.on_item_added)
|
||||
gui_hooks.sidebar_should_refresh_notetypes.remove(self.on_item_added)
|
||||
gui_hooks.operation_will_execute.remove(self.on_operation_will_execute)
|
||||
gui_hooks.operation_did_execute.remove(self.on_operation_did_execute)
|
||||
gui_hooks.focus_did_change.remove(self.on_focus_change)
|
||||
|
||||
def on_unfocus_field(self, changed: bool, note: Note, field_idx: int) -> None:
|
||||
self.refreshCurrentCard(note)
|
||||
|
||||
# covers the tag, note and deck case
|
||||
def on_item_added(self, item: Any = None) -> None:
|
||||
self.sidebar.refresh()
|
||||
|
|
|
@ -90,6 +90,7 @@ _html = """
|
|||
</div>
|
||||
"""
|
||||
|
||||
|
||||
class Editor:
|
||||
"""The screen that embeds an editing widget should listen for changes via
|
||||
the `operation_did_execute` hook, and call set_note() when the editor needs
|
||||
|
|
|
@ -7,6 +7,7 @@ import html
|
|||
import json
|
||||
import re
|
||||
import unicodedata as ucd
|
||||
from enum import Enum, auto
|
||||
from typing import Any, Callable, List, Match, Optional, Sequence, Tuple, Union
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
|
@ -41,6 +42,12 @@ from aqt.utils import (
|
|||
from aqt.webview import AnkiWebView
|
||||
|
||||
|
||||
class RefreshNeeded(Enum):
|
||||
NO = auto()
|
||||
NOTE_TEXT = auto()
|
||||
QUEUES = auto()
|
||||
|
||||
|
||||
class ReviewerBottomBar:
|
||||
def __init__(self, reviewer: Reviewer) -> None:
|
||||
self.reviewer = reviewer
|
||||
|
@ -69,7 +76,7 @@ class Reviewer:
|
|||
self._recordedAudio: Optional[str] = None
|
||||
self.typeCorrect: str = None # web init happens before this is set
|
||||
self.state: Optional[str] = None
|
||||
self._refresh_needed = False
|
||||
self._refresh_needed = RefreshNeeded.NO
|
||||
self.bottom = BottomBar(mw, mw.bottomWeb)
|
||||
hooks.card_did_leech.append(self.onLeech)
|
||||
|
||||
|
@ -78,7 +85,7 @@ class Reviewer:
|
|||
self.web.set_bridge_command(self._linkHandler, self)
|
||||
self.bottom.web.set_bridge_command(self._linkHandler, ReviewerBottomBar(self))
|
||||
self._reps: int = None
|
||||
self._refresh_needed = True
|
||||
self._refresh_needed = RefreshNeeded.QUEUES
|
||||
self.refresh_if_needed()
|
||||
|
||||
def lastCard(self) -> Optional[Card]:
|
||||
|
@ -96,11 +103,15 @@ class Reviewer:
|
|||
self.card = None
|
||||
|
||||
def refresh_if_needed(self) -> None:
|
||||
if self._refresh_needed:
|
||||
if self._refresh_needed is RefreshNeeded.QUEUES:
|
||||
self.mw.col.reset()
|
||||
self.nextCard()
|
||||
self._refresh_needed = False
|
||||
self.mw.fade_in_webview()
|
||||
self._refresh_needed = RefreshNeeded.NO
|
||||
elif self._refresh_needed is RefreshNeeded.NOTE_TEXT:
|
||||
self._redraw_current_card()
|
||||
self.mw.fade_in_webview()
|
||||
self._refresh_needed = RefreshNeeded.NO
|
||||
|
||||
def op_executed(self, changes: OpChanges, focused: bool) -> bool:
|
||||
if changes.note and changes.kind == OpChanges.UPDATE_NOTE_TAGS:
|
||||
|
@ -111,14 +122,21 @@ class Reviewer:
|
|||
self.card.load()
|
||||
self._update_flag_icon()
|
||||
elif self.mw.col.op_affects_study_queue(changes):
|
||||
self._refresh_needed = True
|
||||
self._refresh_needed = RefreshNeeded.QUEUES
|
||||
elif changes.note or changes.notetype or changes.tag:
|
||||
self._refresh_needed = True
|
||||
self._refresh_needed = RefreshNeeded.NOTE_TEXT
|
||||
|
||||
if focused and self._refresh_needed:
|
||||
if focused and self._refresh_needed is not RefreshNeeded.NO:
|
||||
self.refresh_if_needed()
|
||||
|
||||
return self._refresh_needed
|
||||
return self._refresh_needed is not RefreshNeeded.NO
|
||||
|
||||
def _redraw_current_card(self) -> None:
|
||||
self.card.load()
|
||||
if self.state == "answer":
|
||||
self._showAnswer()
|
||||
else:
|
||||
self._showQuestion()
|
||||
|
||||
# Fetching a card
|
||||
##########################################################################
|
||||
|
|
Loading…
Reference in a new issue