From c43a3e79698dcded673676c9df32b67ffb59fedd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 10 Sep 2013 14:13:02 +0530 Subject: [PATCH] Preserve current book when doing searches When doing searches or switching between virtual libraries in the main book list, preserve the current book. The currently selected book will remain visible if it is present in the results of the search or the selected virtual library. Fixes #1216713 [After selecting books which belongs to same serie, when returning to main window, we are at the top of the list and not at previously selected item](https://bugs.launchpad.net/calibre/+bug/1216713) --- src/calibre/gui2/library/alternate_views.py | 32 +++++++++++++++++++ src/calibre/gui2/library/models.py | 2 ++ src/calibre/gui2/library/views.py | 35 ++++++++++++++++++++- 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/library/alternate_views.py b/src/calibre/gui2/library/alternate_views.py index cd8f78202d..d460eec0bb 100644 --- a/src/calibre/gui2/library/alternate_views.py +++ b/src/calibre/gui2/library/alternate_views.py @@ -226,6 +226,7 @@ class AlternateViews(object): self.stack = None self.break_link = False self.main_connected = False + self.current_book_state = None def set_stack(self, stack): self.stack = stack @@ -290,6 +291,15 @@ class AlternateViews(object): for view in self.views.itervalues(): if view is not self.main_view: view.set_context_menu(menu) + + def save_current_book_state(self): + self.current_book_state = self.current_view, self.current_view.current_book_state() + + def restore_current_book_state(self): + if self.current_book_state is not None: + if self.current_book_state[0] is self.current_view: + self.current_view.restore_current_book_state(self.current_book_state[1]) + self.current_book_state = None # }}} # Rendering of covers {{{ @@ -773,4 +783,26 @@ class GridView(QListView): sm.select(QItemSelection(top, bottom), sm.Select) else: return QListView.mousePressEvent(self, ev) + + @property + def current_book(self): + ci = self.currentIndex() + if ci.isValid(): + try: + return self.model().db.data.index_to_id(ci.row()) + except (IndexError, ValueError, KeyError, TypeError, AttributeError): + pass + + def current_book_state(self): + return self.current_book + + def restore_current_book_state(self, state): + book_id = state + try: + row = self.model().db.data.id_to_index(book_id) + except (IndexError, ValueError, KeyError, TypeError, AttributeError): + return + self.set_current_row(row) + self.select_rows((row,)) + self.scrollTo(self.model().index(row, 0), self.PositionAtCenter) # }}} diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 3d46b0e01e..2db64fd8b3 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -120,6 +120,7 @@ class BooksModel(QAbstractTableModel): # {{{ new_bookdisplay_data = pyqtSignal(object) count_changed_signal = pyqtSignal(int) searched = pyqtSignal(object) + search_done = pyqtSignal() def __init__(self, parent=None, buffer=40): QAbstractTableModel.__init__(self, parent) @@ -392,6 +393,7 @@ class BooksModel(QAbstractTableModel): # {{{ # Do not issue search done for the null search. It is used to clear # the search and count records for restrictions self.searched.emit(True) + self.search_done.emit() def sort(self, col, order, reset=True): if not self.db: diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 34896c413f..6711da1d9b 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -149,6 +149,7 @@ class BooksView(QTableView): # {{{ files_dropped = pyqtSignal(object) add_column_signal = pyqtSignal() + is_library_view = True def viewportEvent(self, event): if (event.type() == event.ToolTip and not gprefs['book_list_tooltips']): @@ -776,6 +777,28 @@ class BooksView(QTableView): # {{{ self.scrollTo(self.model().index(row, i), self.PositionAtCenter) break + @property + def current_book(self): + ci = self.currentIndex() + if ci.isValid(): + try: + return self.model().db.data.index_to_id(ci.row()) + except (IndexError, ValueError, KeyError, TypeError, AttributeError): + pass + + def current_book_state(self): + return self.current_book, self.horizontalScrollBar().value() + + def restore_current_book_state(self, state): + book_id, hpos = state + try: + row = self.model().db.data.id_to_index(book_id) + except (IndexError, ValueError, KeyError, TypeError, AttributeError): + return + self.set_current_row(row) + self.scroll_to_row(row) + self.horizontalScrollBar().setValue(hpos) + def set_current_row(self, row=0, select=True, for_sync=False): if row > -1 and row < self.model().rowCount(QModelIndex()): h = self.horizontalHeader() @@ -929,18 +952,26 @@ class BooksView(QTableView): # {{{ self.select_rows([id_to_select], using_ids=True) def search_proxy(self, txt): + if self.is_library_view: + # Save the current book before doing the search, after the search + # is completed, this book will become the current book and be + # scrolled to if it is present in the search results + self.alternate_views.save_current_book_state() self._model.search(txt) id_to_select = self._model.get_current_highlighted_id() if id_to_select is not None: self.select_rows([id_to_select], using_ids=True) elif self._model.highlight_only: self.clearSelection() - self.setFocus(Qt.OtherFocusReason) + if self.isVisible(): + self.setFocus(Qt.OtherFocusReason) def connect_to_search_box(self, sb, search_done): sb.search.connect(self.search_proxy) self._search_done = search_done self._model.searched.connect(self.search_done) + if self.is_library_view: + self._model.search_done.connect(self.alternate_views.restore_current_book_state) def connect_to_book_display(self, bd): self._model.new_bookdisplay_data.connect(bd) @@ -955,6 +986,8 @@ class BooksView(QTableView): # {{{ class DeviceBooksView(BooksView): # {{{ + is_library_view = False + def __init__(self, parent): BooksView.__init__(self, parent, DeviceBooksModel, use_edit_metadata_dialog=False)