mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
experiment with perform_op() wrapper
Fixes #1065, and gives us similar functionality to #1066
This commit is contained in:
parent
2ffc055487
commit
d92f1499ff
1 changed files with 78 additions and 31 deletions
|
@ -475,6 +475,44 @@ class Browser(QMainWindow):
|
||||||
gui_hooks.browser_will_show(self)
|
gui_hooks.browser_will_show(self)
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
|
def perform_op(
|
||||||
|
self,
|
||||||
|
op: Callable,
|
||||||
|
on_done: Callable[[Future], None],
|
||||||
|
*,
|
||||||
|
reset_model: bool = True,
|
||||||
|
) -> None:
|
||||||
|
"""Run the provided operation on a background thread.
|
||||||
|
- Ensures any changes in the editor have been saved.
|
||||||
|
- Shows progress popup for the duration of the op.
|
||||||
|
- Ensures the browser doesn't try to redraw during the operation, which can lead
|
||||||
|
to a frozen UI
|
||||||
|
- Updates undo state at the end of the operation
|
||||||
|
- If `reset_model` is true, calls beginReset()/endReset(), which will
|
||||||
|
refresh the displayed data, and update the editor's note. If the current search
|
||||||
|
has changed results, you will need to call .search() yourself in `on_done`.
|
||||||
|
|
||||||
|
Caller must run fut.result() in the on_done() callback to check for errors;
|
||||||
|
if the operation returned a value, it will be returned by .result()
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapped_op() -> None:
|
||||||
|
if reset_model:
|
||||||
|
self.model.beginReset()
|
||||||
|
self.setUpdatesEnabled(False)
|
||||||
|
op()
|
||||||
|
|
||||||
|
def wrapped_done(fut: Future) -> None:
|
||||||
|
self.setUpdatesEnabled(True)
|
||||||
|
on_done(fut)
|
||||||
|
if reset_model:
|
||||||
|
self.model.endReset()
|
||||||
|
self.mw.update_undo_actions()
|
||||||
|
|
||||||
|
self.editor.saveNow(
|
||||||
|
lambda: self.mw.taskman.with_progress(wrapped_op, wrapped_done)
|
||||||
|
)
|
||||||
|
|
||||||
def setupMenus(self) -> None:
|
def setupMenus(self) -> None:
|
||||||
# pylint: disable=unnecessary-lambda
|
# pylint: disable=unnecessary-lambda
|
||||||
# actions
|
# actions
|
||||||
|
@ -500,9 +538,9 @@ class Browser(QMainWindow):
|
||||||
qconnect(f.actionFindDuplicates.triggered, self.onFindDupes)
|
qconnect(f.actionFindDuplicates.triggered, self.onFindDupes)
|
||||||
qconnect(f.actionFindReplace.triggered, self.onFindReplace)
|
qconnect(f.actionFindReplace.triggered, self.onFindReplace)
|
||||||
qconnect(f.actionManage_Note_Types.triggered, self.mw.onNoteTypes)
|
qconnect(f.actionManage_Note_Types.triggered, self.mw.onNoteTypes)
|
||||||
qconnect(f.actionDelete.triggered, self.deleteNotes)
|
qconnect(f.actionDelete.triggered, self.delete_selected_notes)
|
||||||
# cards
|
# cards
|
||||||
qconnect(f.actionChange_Deck.triggered, self.setDeck)
|
qconnect(f.actionChange_Deck.triggered, self.set_deck_of_selected_cards)
|
||||||
qconnect(f.action_Info.triggered, self.showCardInfo)
|
qconnect(f.action_Info.triggered, self.showCardInfo)
|
||||||
qconnect(f.actionReposition.triggered, self.reposition)
|
qconnect(f.actionReposition.triggered, self.reposition)
|
||||||
qconnect(f.action_set_due_date.triggered, self.set_due_date)
|
qconnect(f.action_set_due_date.triggered, self.set_due_date)
|
||||||
|
@ -1122,55 +1160,62 @@ where id in %s"""
|
||||||
# Card deletion
|
# Card deletion
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def deleteNotes(self) -> None:
|
def delete_selected_notes(self) -> None:
|
||||||
|
# ensure deletion is not accidentally triggered when the user is focused
|
||||||
|
# in the editing screen or search bar
|
||||||
focus = self.focusWidget()
|
focus = self.focusWidget()
|
||||||
if focus != self.form.tableView:
|
if focus != self.form.tableView:
|
||||||
return
|
return
|
||||||
self._deleteNotes()
|
|
||||||
|
|
||||||
def _deleteNotes(self) -> None:
|
# nothing selected?
|
||||||
nids = self.selectedNotes()
|
nids = self.selectedNotes()
|
||||||
if not nids:
|
if not nids:
|
||||||
return
|
return
|
||||||
self.mw.checkpoint(tr(TR.BROWSING_DELETE_NOTES))
|
|
||||||
self.model.beginReset()
|
|
||||||
# figure out where to place the cursor after the deletion
|
# figure out where to place the cursor after the deletion
|
||||||
curRow = self.form.tableView.selectionModel().currentIndex().row()
|
current_row = self.form.tableView.selectionModel().currentIndex().row()
|
||||||
selectedRows = [
|
selected_rows = [
|
||||||
i.row() for i in self.form.tableView.selectionModel().selectedRows()
|
i.row() for i in self.form.tableView.selectionModel().selectedRows()
|
||||||
]
|
]
|
||||||
if min(selectedRows) < curRow < max(selectedRows):
|
if min(selected_rows) < current_row < max(selected_rows):
|
||||||
# last selection in middle; place one below last selected item
|
# last selection in middle; place one below last selected item
|
||||||
move = sum(1 for i in selectedRows if i > curRow)
|
move = sum(1 for i in selected_rows if i > current_row)
|
||||||
newRow = curRow - move
|
new_row = current_row - move
|
||||||
elif max(selectedRows) <= curRow:
|
elif max(selected_rows) <= current_row:
|
||||||
# last selection at bottom; place one below bottommost selection
|
# last selection at bottom; place one below bottommost selection
|
||||||
newRow = max(selectedRows) - len(nids) + 1
|
new_row = max(selected_rows) - len(nids) + 1
|
||||||
else:
|
else:
|
||||||
# last selection at top; place one above topmost selection
|
# last selection at top; place one above topmost selection
|
||||||
newRow = min(selectedRows) - 1
|
new_row = min(selected_rows) - 1
|
||||||
|
|
||||||
|
def do_remove() -> None:
|
||||||
self.col.remove_notes(nids)
|
self.col.remove_notes(nids)
|
||||||
|
|
||||||
|
def on_done(fut: Future) -> None:
|
||||||
|
fut.result()
|
||||||
self.search()
|
self.search()
|
||||||
if len(self.model.cards):
|
if len(self.model.cards):
|
||||||
newRow = min(newRow, len(self.model.cards) - 1)
|
row = min(new_row, len(self.model.cards) - 1)
|
||||||
newRow = max(newRow, 0)
|
row = max(row, 0)
|
||||||
self.model.focusedCard = self.model.cards[newRow]
|
self.model.focusedCard = self.model.cards[row]
|
||||||
self.model.endReset()
|
|
||||||
self.mw.reset()
|
|
||||||
tooltip(tr(TR.BROWSING_NOTE_DELETED, count=len(nids)))
|
tooltip(tr(TR.BROWSING_NOTE_DELETED, count=len(nids)))
|
||||||
|
|
||||||
|
self.perform_op(do_remove, on_done, reset_model=True)
|
||||||
|
|
||||||
|
# legacy
|
||||||
|
|
||||||
|
deleteNotes = delete_selected_notes
|
||||||
|
|
||||||
# Deck change
|
# Deck change
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def setDeck(self) -> None:
|
def set_deck_of_selected_cards(self) -> None:
|
||||||
self.editor.saveNow(self._setDeck)
|
|
||||||
|
|
||||||
def _setDeck(self) -> None:
|
|
||||||
from aqt.studydeck import StudyDeck
|
from aqt.studydeck import StudyDeck
|
||||||
|
|
||||||
cids = self.selectedCards()
|
cids = self.selectedCards()
|
||||||
if not cids:
|
if not cids:
|
||||||
return
|
return
|
||||||
|
|
||||||
did = self.mw.col.db.scalar("select did from cards where id = ?", cids[0])
|
did = self.mw.col.db.scalar("select did from cards where id = ?", cids[0])
|
||||||
current = self.mw.col.decks.get(did)["name"]
|
current = self.mw.col.decks.get(did)["name"]
|
||||||
ret = StudyDeck(
|
ret = StudyDeck(
|
||||||
|
@ -1184,17 +1229,19 @@ where id in %s"""
|
||||||
if not ret.name:
|
if not ret.name:
|
||||||
return
|
return
|
||||||
did = self.col.decks.id(ret.name)
|
did = self.col.decks.id(ret.name)
|
||||||
self.model.beginReset()
|
|
||||||
|
|
||||||
def do_move() -> None:
|
def do_move() -> None:
|
||||||
self.col.set_deck(cids, did)
|
self.col.set_deck(cids, did)
|
||||||
|
|
||||||
def on_done(fut: Future) -> None:
|
def on_done(fut: Future) -> None:
|
||||||
self.model.endReset()
|
|
||||||
fut.result()
|
fut.result()
|
||||||
self.mw.requireReset(reason=ResetReason.BrowserSetDeck, context=self)
|
self.mw.requireReset(reason=ResetReason.BrowserSetDeck, context=self)
|
||||||
|
|
||||||
self.mw.taskman.with_progress(do_move, on_done)
|
self.perform_op(do_move, on_done)
|
||||||
|
|
||||||
|
# legacy
|
||||||
|
|
||||||
|
setDeck = set_deck_of_selected_cards
|
||||||
|
|
||||||
# Tags
|
# Tags
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
Loading…
Reference in a new issue