shift keep-current-selection logic into sidebar's refresh()

By calling refresh() manually after performing an op, we were refreshing
twice, and the selection was being lost when changes were made outside
of the sidebar.

Also drop the after_hooks arg to perform_op(), since nothing is using
it now.
This commit is contained in:
Damien Elmes 2021-04-06 11:18:13 +10:00
parent 3f62f54f14
commit 1ece868d02
4 changed files with 37 additions and 41 deletions

View File

@ -771,7 +771,6 @@ class AnkiQt(QMainWindow):
*, *,
success: PerformOpOptionalSuccessCallback = None, success: PerformOpOptionalSuccessCallback = None,
failure: PerformOpOptionalFailureCallback = None, failure: PerformOpOptionalFailureCallback = None,
after_hooks: Optional[Callable[[], None]] = None,
handler: Optional[object] = None, handler: Optional[object] = None,
) -> None: ) -> None:
"""Run the provided operation on a background thread. """Run the provided operation on a background thread.
@ -795,10 +794,6 @@ class AnkiQt(QMainWindow):
If op() throws an exception, it will be shown in a popup, or If op() throws an exception, it will be shown in a popup, or
passed to failure() if it is provided. passed to failure() if it is provided.
after_hooks() will be called after hooks are fired, if it is provided.
Components can use this to ignore change notices generated by operations
they invoke themselves, or perform some subsequent action.
""" """
self._increase_background_ops() self._increase_background_ops()
@ -826,7 +821,7 @@ class AnkiQt(QMainWindow):
status = self.col.undo_status() status = self.col.undo_status()
self._update_undo_actions_for_status_and_save(status) self._update_undo_actions_for_status_and_save(status)
# fire change hooks # fire change hooks
self._fire_change_hooks_after_op_performed(result, after_hooks, handler) self._fire_change_hooks_after_op_performed(result, handler)
self.taskman.with_progress(op, wrapped_done) self.taskman.with_progress(op, wrapped_done)
@ -844,7 +839,6 @@ class AnkiQt(QMainWindow):
def _fire_change_hooks_after_op_performed( def _fire_change_hooks_after_op_performed(
self, self,
result: ResultWithChanges, result: ResultWithChanges,
after_hooks: Optional[Callable[[], None]],
handler: Optional[object], handler: Optional[object],
) -> None: ) -> None:
if isinstance(result, OpChanges): if isinstance(result, OpChanges):
@ -859,8 +853,6 @@ class AnkiQt(QMainWindow):
# fire legacy hook so old code notices changes # fire legacy hook so old code notices changes
if self.col.op_made_changes(changes): if self.col.op_made_changes(changes):
gui_hooks.state_did_reset() gui_hooks.state_did_reset()
if after_hooks:
after_hooks()
def _synthesize_op_did_execute_from_reset(self) -> None: def _synthesize_op_did_execute_from_reset(self) -> None:
"""Fire the `operation_did_execute` hook with everything marked as changed, """Fire the `operation_did_execute` hook with everything marked as changed,

View File

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
from typing import Callable, Optional, Sequence from typing import Optional, Sequence
from anki.decks import DeckCollapseScope, DeckId from anki.decks import DeckCollapseScope, DeckId
from aqt import AnkiQt, QWidget from aqt import AnkiQt, QWidget
@ -41,10 +41,9 @@ def rename_deck(
mw: AnkiQt, mw: AnkiQt,
deck_id: DeckId, deck_id: DeckId,
new_name: str, new_name: str,
after_rename: Callable[[], None] = None,
) -> None: ) -> None:
mw.perform_op( mw.perform_op(
lambda: mw.col.decks.rename(deck_id, new_name), after_hooks=after_rename lambda: mw.col.decks.rename(deck_id, new_name),
) )

View File

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
from typing import Callable, Optional, Sequence from typing import Optional, Sequence
from anki.collection import OpChangesWithCount from anki.collection import OpChangesWithCount
from anki.notes import NoteId from anki.notes import NoteId
@ -57,7 +57,6 @@ def rename_tag(
parent: QWidget, parent: QWidget,
current_name: str, current_name: str,
new_name: str, new_name: str,
after_rename: Callable[[], None],
) -> None: ) -> None:
def success(out: OpChangesWithCount) -> None: def success(out: OpChangesWithCount) -> None:
if out.count: if out.count:
@ -68,7 +67,6 @@ def rename_tag(
mw.perform_op( mw.perform_op(
lambda: mw.col.tags.rename(old=current_name, new=new_name), lambda: mw.col.tags.rename(old=current_name, new=new_name),
success=success, success=success,
after_hooks=after_rename,
) )

View File

@ -172,6 +172,18 @@ class SidebarItem:
) )
return self._search_matches_self or self._search_matches_child return self._search_matches_self or self._search_matches_child
def has_same_id(self, other: SidebarItem) -> bool:
"True if `other` is same type, with same id/name."
if other.item_type == self.item_type:
if self.item_type == SidebarItemType.TAG:
return self.full_name == other.full_name
elif self.item_type == SidebarItemType.SAVED_SEARCH:
return self.name == other.name
else:
return other.id == self.id
return False
class SidebarModel(QAbstractItemModel): class SidebarModel(QAbstractItemModel):
def __init__(self, sidebar: SidebarTreeView, root: SidebarItem) -> None: def __init__(self, sidebar: SidebarTreeView, root: SidebarItem) -> None:
@ -432,13 +444,16 @@ class SidebarTreeView(QTreeView):
self.refresh() self.refresh()
self._refresh_needed = False self._refresh_needed = False
def refresh( def refresh(self) -> None:
self, is_current: Optional[Callable[[SidebarItem], bool]] = None
) -> None:
"Refresh list. No-op if sidebar is not visible." "Refresh list. No-op if sidebar is not visible."
if not self.isVisible(): if not self.isVisible():
return return
if self.model() and (idx := self.currentIndex()):
current_item = self.model().item_for_index(idx)
else:
current_item = None
def on_done(root: SidebarItem) -> None: def on_done(root: SidebarItem) -> None:
# user may have closed browser # user may have closed browser
if sip.isdeleted(self): if sip.isdeleted(self):
@ -454,8 +469,8 @@ class SidebarTreeView(QTreeView):
self.search_for(self.current_search) self.search_for(self.current_search)
else: else:
self._expand_where_necessary(model) self._expand_where_necessary(model)
if is_current: if current_item:
self.restore_current(is_current) self.restore_current(current_item)
self.setUpdatesEnabled(True) self.setUpdatesEnabled(True)
@ -464,8 +479,8 @@ class SidebarTreeView(QTreeView):
self.mw.query_op(self._root_tree, success=on_done) self.mw.query_op(self._root_tree, success=on_done)
def restore_current(self, is_current: Callable[[SidebarItem], bool]) -> None: def restore_current(self, current: SidebarItem) -> None:
if current := self.find_item(is_current): if current := self.find_item(current.has_same_id):
index = self.model().index_for_item(current) index = self.model().index_for_item(current)
self.selectionModel().setCurrentIndex( self.selectionModel().setCurrentIndex(
index, QItemSelectionModel.SelectCurrent index, QItemSelectionModel.SelectCurrent
@ -1165,21 +1180,21 @@ class SidebarTreeView(QTreeView):
def rename_deck(self, item: SidebarItem, new_name: str) -> None: def rename_deck(self, item: SidebarItem, new_name: str) -> None:
if not new_name: if not new_name:
return return
new_name = item.name_prefix + new_name
# update UI immediately, to avoid redraw
item.name = new_name
full_name = item.name_prefix + new_name
deck_id = DeckId(item.id) deck_id = DeckId(item.id)
def after_fetch(deck: Deck) -> None: def after_fetch(deck: Deck) -> None:
if new_name == deck.name: if full_name == deck.name:
return return
rename_deck( rename_deck(
mw=self.mw, mw=self.mw,
deck_id=deck_id, deck_id=deck_id,
new_name=new_name, new_name=full_name,
after_rename=lambda: self.refresh(
lambda other: other.item_type == SidebarItemType.DECK
and other.id == item.id
),
) )
self.mw.query_op(lambda: self.mw.col.get_deck(deck_id), success=after_fetch) self.mw.query_op(lambda: self.mw.col.get_deck(deck_id), success=after_fetch)
@ -1208,16 +1223,13 @@ class SidebarTreeView(QTreeView):
new_name = item.name_prefix + new_name new_name = item.name_prefix + new_name
item.name = new_name_base item.name = new_name_base
item.full_name = new_name
rename_tag( rename_tag(
mw=self.mw, mw=self.mw,
parent=self.browser, parent=self.browser,
current_name=old_name, current_name=old_name,
new_name=new_name, new_name=new_name,
after_rename=lambda: self.refresh(
lambda item: item.item_type == SidebarItemType.TAG
and item.full_name == new_name
),
) )
# Saved searches # Saved searches
@ -1250,10 +1262,7 @@ class SidebarTreeView(QTreeView):
return return
conf[name] = search conf[name] = search
self._set_saved_searches(conf) self._set_saved_searches(conf)
self.refresh( self.refresh()
lambda item: item.item_type == SidebarItemType.SAVED_SEARCH
and item.name == name
)
def remove_saved_searches(self, _item: SidebarItem) -> None: def remove_saved_searches(self, _item: SidebarItem) -> None:
selected = self._selected_saved_searches() selected = self._selected_saved_searches()
@ -1277,10 +1286,8 @@ class SidebarTreeView(QTreeView):
conf[new_name] = filt conf[new_name] = filt
del conf[old_name] del conf[old_name]
self._set_saved_searches(conf) self._set_saved_searches(conf)
self.refresh( item.name = new_name
lambda item: item.item_type == SidebarItemType.SAVED_SEARCH self.refresh()
and item.name == new_name
)
def save_current_search(self) -> None: def save_current_search(self) -> None:
if (search := self._get_current_search()) is None: if (search := self._get_current_search()) is None: