diff --git a/manual/gui.rst b/manual/gui.rst index 0da076c2c0..4df3ef12c7 100644 --- a/manual/gui.rst +++ b/manual/gui.rst @@ -700,6 +700,12 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes - Restart calibre in debug mode * - :kbd:`Shift+Ctrl+E` - Add empty books to calibre + * - :kbd:`Q` + - Open the Quick View popup for viewing books in related series/tags/etc. + * - :kbd:`Shift+Q` + - Focus the opened Quick View panel + * - :kbd:`Shift+S` + - Perform a search in the Quick View panel * - :kbd:`Ctrl+Q` - Quit calibre diff --git a/src/calibre/gui2/actions/show_quickview.py b/src/calibre/gui2/actions/show_quickview.py index 90de2d2d93..7071b3c1bd 100644 --- a/src/calibre/gui2/actions/show_quickview.py +++ b/src/calibre/gui2/actions/show_quickview.py @@ -32,6 +32,14 @@ class ShowQuickviewAction(InterfaceAction): group=self.action_spec[0]) self.focus_action.triggered.connect(self.focus_quickview) + self.search_action = QAction(self.gui) + self.gui.addAction(self.search_action) + self.gui.keyboard.register_shortcut('Search from Quickview', _('Search from Quickview'), + description=_('Search for the currently selected Quickview item'), + default_keys=('Shift+S',), action=self.search_action, + group=self.action_spec[0]) + self.search_action.triggered.connect(self.search_quickview) + def show_quickview(self, *args): if self.current_instance: if not self.current_instance.is_closed: @@ -71,3 +79,8 @@ class ShowQuickviewAction(InterfaceAction): if not (self.current_instance and not self.current_instance.is_closed): self.show_quickview() self.current_instance.set_focus() + + def search_quickview(self): + if not self.current_instance or self.current_instance.is_closed: + return + self.current_instance.do_search() diff --git a/src/calibre/gui2/dialogs/quickview.py b/src/calibre/gui2/dialogs/quickview.py index e496e346f6..1d2d0f3ad9 100644 --- a/src/calibre/gui2/dialogs/quickview.py +++ b/src/calibre/gui2/dialogs/quickview.py @@ -51,7 +51,7 @@ IN_WIDGET_DOCK = 3 IN_WIDGET_SEARCH = 4 IN_WIDGET_CLOSE = 5 -class BooksKeyPressFilter(QObject): +class BooksTableFilter(QObject): return_pressed_signal = pyqtSignal() @@ -61,6 +61,15 @@ class BooksKeyPressFilter(QObject): return True return False +class WidgetFocusFilter(QObject): + + focus_entered_signal = pyqtSignal(object) + + def eventFilter(self, obj, event): + if event.type() == QEvent.FocusIn: + self.focus_entered_signal.emit(obj) + return False + class WidgetTabFilter(QObject): def __init__(self, attach_to_Class, which_widget, tab_signal): @@ -132,13 +141,22 @@ class Quickview(QDialog, Ui_Quickview): self.items.setSelectionMode(QAbstractItemView.SingleSelection) self.items.currentTextChanged.connect(self.item_selected) + self.items.setProperty('highlight_current_item', 150) + + focus_filter = WidgetFocusFilter(self.items) + focus_filter.focus_entered_signal.connect(self.focus_entered) + self.items.installEventFilter(focus_filter) self.tab_pressed_signal.connect(self.tab_pressed) # Set up the books table columns - return_filter = BooksKeyPressFilter(self.books_table) + return_filter = BooksTableFilter(self.books_table) return_filter.return_pressed_signal.connect(self.return_pressed) self.books_table.installEventFilter(return_filter) + focus_filter = WidgetFocusFilter(self.books_table) + focus_filter.focus_entered_signal.connect(self.focus_entered) + self.books_table.installEventFilter(focus_filter) + self.close_button = self.buttonBox.button(QDialogButtonBox.Close) self.tab_order_widgets = [self.items, self.books_table, self.lock_qv, @@ -148,6 +166,7 @@ class Quickview(QDialog, Ui_Quickview): self.books_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.books_table.setSelectionMode(QAbstractItemView.SingleSelection) + self.books_table.setProperty('highlight_current_item', 150) self.books_table.setColumnCount(3) t = QTableWidgetItem(_('Title')) self.books_table.setHorizontalHeaderItem(self.title_column, t) @@ -157,6 +176,9 @@ class Quickview(QDialog, Ui_Quickview): self.books_table.setHorizontalHeaderItem(self.series_column, t) self.books_table_header_height = self.books_table.height() self.books_table.cellDoubleClicked.connect(self.book_doubleclicked) + self.books_table.currentCellChanged.connect(self.books_table_cell_changed) + self.books_table.cellClicked.connect(self.books_table_set_search_string) + self.books_table.cellActivated.connect(self.books_table_set_search_string) self.books_table.sortByColumn(self.title_column, Qt.AscendingOrder) # get the standard table row height. Do this here because calling @@ -178,6 +200,7 @@ class Quickview(QDialog, Ui_Quickview): self.view.model().new_bookdisplay_data.connect(self.book_was_changed) self.close_button.setDefault(False) + self.search_button.setToolTip(_('Search in the library view for the currently highlighted selection')) if self.is_pane: self.dock_button.setText(_('Undock')) self.dock_button.setToolTip(_('Pop up the quickview panel into its own floating window')) @@ -185,9 +208,11 @@ class Quickview(QDialog, Ui_Quickview): self.lock_qv.setText(_('Lock Quickview contents')) self.search_button.setText(_('Search')) self.gui.quickview_splitter.add_quickview_dialog(self) + self.search_button.setToolTip(self.search_button.toolTip() + _(' (has shortcut)')) + self.close_button.setToolTip(_('The Quickview shortcut toggles this pane on/off')) else: - self.lock_qv.setText(_('&Dock')) self.close_button.setText(_('&Close')) + self.dock_button.setText(_('&Dock')) self.dock_button.setToolTip(_('Embed the quickview panel into the main calibre window')) self.dock_button.setIcon(QIcon(I('arrow-down.png'))) self.set_focus() @@ -195,6 +220,41 @@ class Quickview(QDialog, Ui_Quickview): self.books_table.horizontalHeader().sectionResized.connect(self.section_resized) self.dock_button.clicked.connect(self.show_as_pane_changed) + def set_search_text(self, txt): + if txt: + self.search_button.setEnabled(True) + else: + self.search_button.setEnabled(False) + self.last_search = txt + + def focus_entered(self, obj): + if obj == self.books_table: + self.books_table_set_search_string(self.books_table.currentRow(), + self.books_table.currentColumn()) + elif obj.currentItem(): + self.item_selected(obj.currentItem().text()) + + def books_table_cell_changed(self, cur_row, cur_col, prev_row, prev_col): + self.books_table_set_search_string(cur_row, cur_col) + + def books_table_set_search_string(self, current_row, current_col): + current = self.books_table.currentItem() + if current is None: + return + if current.column() == 0: + self.set_search_text('title:="' + current.text().replace('"', '\\"') + '"') + elif current.column() == 1: + authors = [] + for aut in [t.strip() for t in current.text().split('&')]: + authors.append('authors:="' + aut.replace('"', '\\"') + '"') + self.set_search_text(' and '.join(authors)) + else: + t = current.text().rpartition('[')[0].strip() + if t: + self.set_search_text('series:="' + t.replace('"', '\\"') + '"') + else: + self.set_search_text(None) + def tab_pressed(self, in_widget, isForward): if isForward: in_widget += 1 @@ -244,6 +304,7 @@ class Quickview(QDialog, Ui_Quickview): if self.no_valid_items: return self.fill_in_books_box(unicode(txt)) + self.set_search_text(self.current_key + ':"=' + txt.replace('"', '\\"') + '"') # Given a cell in the library view, display the information def refresh(self, idx): @@ -312,9 +373,8 @@ class Quickview(QDialog, Ui_Quickview): sv = '.' + selected_item else: sv = selected_item - sv = sv.replace('"', r'\"') - self.last_search = self.current_key+':"=' + sv + '"' - books = self.db.search(self.last_search, return_matches=True, + sv = self.current_key + ':"=' + sv.replace('"', r'\"') + '"' + books = self.db.search(sv, return_matches=True, sort_results=False) self.books_table.setRowCount(len(books)) @@ -352,6 +412,7 @@ class Quickview(QDialog, Ui_Quickview): if select_item is not None: self.books_table.setCurrentItem(select_item) self.books_table.scrollToItem(select_item, QAbstractItemView.PositionAtCenter) + self.set_search_text(sv) # Deal with sizing the table columns. Done here because the numbers are not # correct until the first paint. @@ -393,7 +454,7 @@ class Quickview(QDialog, Ui_Quickview): em.actual_plugin_.edit_metadata(None) def set_focus(self): - self.books_table.setFocus(Qt.ActiveWindowFocusReason) + self.items.setFocus(Qt.ActiveWindowFocusReason) # called when a book is clicked on the library view def slave(self, current): diff --git a/src/calibre/gui2/dialogs/quickview.ui b/src/calibre/gui2/dialogs/quickview.ui index 934744c338..2f22f193c3 100644 --- a/src/calibre/gui2/dialogs/quickview.ui +++ b/src/calibre/gui2/dialogs/quickview.ui @@ -115,7 +115,7 @@ &Search - Search in the library view for the selected item + Search in the library view for the currently highlighted selection false