diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 4950c76745..1313241101 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -155,7 +155,7 @@ def create_defs(): defs['qv_respects_vls'] = True defs['qv_dclick_changes_column'] = True defs['qv_retkey_changes_column'] = True - defs['qv_show_on_startup'] = False + defs['qv_follows_column'] = False create_defs() diff --git a/src/calibre/gui2/actions/show_quickview.py b/src/calibre/gui2/actions/show_quickview.py index 1c5d58df40..ba80a802ff 100644 --- a/src/calibre/gui2/actions/show_quickview.py +++ b/src/calibre/gui2/actions/show_quickview.py @@ -10,8 +10,37 @@ from PyQt5.Qt import QAction from calibre.gui2.actions import InterfaceAction from calibre.gui2.dialogs.quickview import Quickview -from calibre.gui2 import error_dialog +from calibre.gui2 import error_dialog, gprefs +from calibre.gui2.widgets import LayoutButton +class QuickviewButton(LayoutButton): # {{{ + + def __init__(self, gui, quickview_manager): + self.qv = quickview_manager + qaction = quickview_manager.qaction + LayoutButton.__init__(self, I('eye-quickview.png'), _('Quickview'), + parent=gui, shortcut=qaction.shortcut().toString()) + self.action_toggle = qaction + self.action_toggle.triggered.connect(self.toggle) + self.action_toggle.changed.connect(self.update_shortcut) + + def update_state(self, checked): + if checked: + self.set_state_to_hide() + self.qv._show_quickview() + else: + self.set_state_to_show() + self.qv._hide_quickview() + + def save_state(self): + gprefs['quickview visible'] = bool(self.isChecked()) + + def restore_state(self): + self.toggled.connect(self.update_state) + if gprefs.get('quickview visible', False): + self.toggle() + +# }}} class ShowQuickviewAction(InterfaceAction): @@ -23,8 +52,6 @@ class ShowQuickviewAction(InterfaceAction): current_instance = None def genesis(self): - self.qaction.triggered.connect(self.show_quickview) - self.focus_action = QAction(self.gui) self.gui.addAction(self.focus_action) self.gui.keyboard.register_shortcut('Focus To Quickview', _('Focus to Quickview'), @@ -42,55 +69,83 @@ class ShowQuickviewAction(InterfaceAction): self.search_action.triggered.connect(self.search_quickview) self.search_action.changed.connect(self.set_search_shortcut) self.menuless_qaction.changed.connect(self.set_search_shortcut) + self.qv_button = QuickviewButton(self.gui, self) - def show_quickview(self, *args): + def _hide_quickview(self): + ''' + This is called only from the QV button toggle + ''' if self.current_instance: if not self.current_instance.is_closed: - self.current_instance.reject() - self.current_instance = None - return + self.current_instance._reject() + self.current_instance = None + + def _show_quickview(self, *args): + ''' + This is called only from the QV button toggle + ''' + if self.current_instance: + if not self.current_instance.is_closed: + self.current_instance._reject() self.current_instance = None if self.gui.current_view() is not self.gui.library_view: error_dialog(self.gui, _('No quickview available'), _('Quickview is not available for books ' 'on the device.')).exec_() return + self.qv_button.set_state_to_hide() index = self.gui.library_view.currentIndex() self.current_instance = Quickview(self.gui, index) - self.current_instance.reopen_quickview.connect(self.reopen_quickview) + self.current_instance.reopen_after_dock_change.connect(self.open_quickview) self.set_search_shortcut() self.current_instance.show() + self.current_instance.quickview_closed.connect(self.qv_button.set_state_to_show) def set_search_shortcut(self): if self.current_instance and not self.current_instance.is_closed: self.current_instance.set_shortcuts(self.search_action.shortcut().toString(), self.menuless_qaction.shortcut().toString()) - def reopen_quickview(self): + def open_quickview(self): + ''' + QV moved from/to dock. Close and reopen the pane/window. + Also called when QV is closed and the user asks to move the focus + ''' if self.current_instance and not self.current_instance.is_closed: self.current_instance.reject() self.current_instance = None - self.show_quickview() + self.qaction.triggered.emit() def refill_quickview(self): + ''' + Called when the data or the columns shown in the QV pane might have changed. + ''' if self.current_instance and not self.current_instance.is_closed: self.current_instance.refill() def change_quickview_column(self, idx): - self.show_quickview() - if self.current_instance: - if self.current_instance.is_closed: - return - self.current_instance.change_quickview_column.emit(idx) + ''' + Called from the column header context menu to change the QV query column + ''' + self.focus_quickview() + self.current_instance.slave(idx) def library_changed(self, db): + ''' + If QV is open, close it then reopen it so the columns are correct + ''' if self.current_instance and not self.current_instance.is_closed: self.current_instance.reject() + self.qaction.triggered.emit() def focus_quickview(self): - if not (self.current_instance and not self.current_instance.is_closed): - self.show_quickview() - self.current_instance.set_focus() + ''' + Used to move the focus to the QV books table. Open QV if needed + ''' + if not self.current_instance or self.current_instance.is_closed: + self.open_quickview() + else: + self.current_instance.set_focus() def search_quickview(self): if not self.current_instance or self.current_instance.is_closed: diff --git a/src/calibre/gui2/dialogs/quickview.py b/src/calibre/gui2/dialogs/quickview.py index 8b7f5141d7..ead75afd2e 100644 --- a/src/calibre/gui2/dialogs/quickview.py +++ b/src/calibre/gui2/dialogs/quickview.py @@ -95,21 +95,22 @@ class WidgetTabFilter(QObject): class Quickview(QDialog, Ui_Quickview): - change_quickview_column = pyqtSignal(object) - reopen_quickview = pyqtSignal() - tab_pressed_signal = pyqtSignal(object, object) + reopen_after_dock_change = pyqtSignal() + tab_pressed_signal = pyqtSignal(object, object) + quickview_closed = pyqtSignal() def __init__(self, gui, row): self.is_pane = gprefs.get('quickview_is_pane', False) if not self.is_pane: - QDialog.__init__(self, gui, flags=Qt.Window) + QDialog.__init__(self, gui, flags=Qt.Widget) else: QDialog.__init__(self, gui) Ui_Quickview.__init__(self) self.setupUi(self) self.isClosed = False self.current_book = None + self.closed_by_button = False if self.is_pane: self.main_grid_layout.setContentsMargins(0, 0, 0, 0) @@ -160,7 +161,7 @@ class Quickview(QDialog, Ui_Quickview): focus_filter.focus_entered_signal.connect(self.focus_entered) self.books_table.installEventFilter(focus_filter) - self.close_button = self.buttonBox.button(QDialogButtonBox.Close) + self.close_button.clicked.connect(self.close_button_clicked) self.tab_order_widgets = [self.items, self.books_table, self.lock_qv, self.dock_button, self.search_button, self.close_button] @@ -194,7 +195,7 @@ class Quickview(QDialog, Ui_Quickview): self.refresh(row) self.view.clicked.connect(self.slave) - self.change_quickview_column.connect(self.slave) + self.view.selectionModel().currentColumnChanged.connect(self.column_slave) QCoreApplication.instance().aboutToQuit.connect(self.save_state) self.search_button.clicked.connect(self.do_search) self.view.model().new_bookdisplay_data.connect(self.book_was_changed) @@ -210,9 +211,8 @@ 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.close_button.setVisible(False) else: - 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() @@ -314,7 +314,7 @@ class Quickview(QDialog, Ui_Quickview): def show_as_pane_changed(self): gprefs['quickview_is_pane'] = not gprefs.get('quickview_is_pane', False) - self.reopen_quickview.emit() + self.reopen_after_dock_change.emit() # search button def do_search(self): @@ -544,10 +544,20 @@ class Quickview(QDialog, Ui_Quickview): self.view.column_map.index(key)) def set_focus(self): - self.items.setFocus(Qt.ActiveWindowFocusReason) + self.activateWindow() + self.books_table.setFocus() + + def column_slave(self, current): + ''' + called when the column is changed on the booklist + ''' + if gprefs['qv_follows_column']: + self.slave(current) - # called when a book is clicked on the library view def slave(self, current): + ''' + called when a book is clicked on the library view + ''' if self.is_closed: return self.refresh(current) @@ -572,8 +582,17 @@ class Quickview(QDialog, Ui_Quickview): self.db = self.view = self.gui = None self.is_closed = True - # called by the close button + def close_button_clicked(self): + self.closed_by_button = True + self.quickview_closed.emit() + def reject(self): + if not self.closed_by_button: + self.close_button_clicked() + else: + self._reject() + + def _reject(self): if self.is_pane: self.gui.quickview_splitter.hide_quickview_widget() self.gui.library_view.setFocus(Qt.ActiveWindowFocusReason) diff --git a/src/calibre/gui2/dialogs/quickview.ui b/src/calibre/gui2/dialogs/quickview.ui index f0517e00b4..3f1b6c497c 100644 --- a/src/calibre/gui2/dialogs/quickview.ui +++ b/src/calibre/gui2/dialogs/quickview.ui @@ -149,11 +149,11 @@ - - - QDialogButtonBox::Close + + + &Close - + false @@ -176,22 +176,4 @@ - - - buttonBox - rejected() - Quickview - reject() - - - 297 - 217 - - - 286 - 234 - - - - diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 16aec295e9..75c3b7e406 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -23,6 +23,7 @@ from calibre.gui2.tag_browser.ui import TagBrowserWidget from calibre.gui2.book_details import BookDetails from calibre.gui2.notify import get_notifier from calibre.gui2.layout_menu import LayoutMenu +from calibre.customize.ui import find_plugin _keep_refs = [] @@ -552,7 +553,7 @@ class LayoutMixin(object): # {{{ self.bd_splitter.addWidget(self.book_details) self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False) self.centralwidget.layout().addWidget(self.bd_splitter) - button_order = ('sb', 'tb', 'bd', 'gv', 'cb') + button_order = ('sb', 'tb', 'bd', 'gv', 'cb', 'qv') # }}} else: # wide {{{ self.bd_splitter = Splitter('book_details_splitter', @@ -567,9 +568,13 @@ class LayoutMixin(object): # {{{ self.bd_splitter.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.centralwidget.layout().addWidget(self.bd_splitter) - button_order = ('sb', 'tb', 'cb', 'gv', 'bd') + button_order = ('sb', 'tb', 'cb', 'gv', 'bd', 'qv') # }}} + self.qv = find_plugin('Show Quickview') + if self.qv: + self.qv = self.qv.actual_plugin_ + self.status_bar = StatusBar(self) stylename = unicode(self.style().objectName()) self.grid_view_button = GridViewButton(self) @@ -582,7 +587,12 @@ class LayoutMixin(object): # {{{ if hasattr(self, x + '_splitter'): button = getattr(self, x + '_splitter').button else: - button = self.grid_view_button if x == 'gv' else self.search_bar_button + if x == 'gv': + button = self.grid_view_button + elif x == 'qv': + button = self.qv.qv_button + else: + button = self.search_bar_button self.layout_buttons.append(button) button.setVisible(False) if isosx and stylename != u'Calibre': @@ -722,6 +732,8 @@ class LayoutMixin(object): # {{{ s.save_state() self.grid_view_button.save_state() self.search_bar_button.save_state() + if self.qv: + self.qv.qv_button.save_state() def read_layout_settings(self): # View states are restored automatically when set_database is called @@ -729,6 +741,7 @@ class LayoutMixin(object): # {{{ getattr(self, x+'_splitter').restore_state() self.grid_view_button.restore_state() self.search_bar_button.restore_state() + # Can't do quickview here because the gui isn't totally set up. Do it in ui def update_status_bar(self, *args): v = self.current_view() diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index bc238796b2..0a50148705 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -387,7 +387,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('qv_respects_vls', gprefs) r('qv_dclick_changes_column', gprefs) r('qv_retkey_changes_column', gprefs) - r('qv_show_on_startup', gprefs) + r('qv_follows_column', gprefs) r('cover_flow_queue_length', config, restart_required=True) r('cover_browser_reflections', gprefs) diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index 73559635ea..01071e4dc6 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -1142,25 +1142,30 @@ them to all have the same width and height - + &Apply virtual libraries in Quickview pane Check this box to make Quickview show books only in the -current virtual library. If unchecked, Quickview ignores virtual libraries. +current virtual library. If unchecked, Quickview ignores virtual libraries. If +unchecked then only row changes are taken into account. - - + + - &Show Quickview on startup + &Change QV item when book list column changes + + + Check this box to make Quickview change the column being examined +when the column in the book list is changed using the cursor arrow keys - + Pressing return in a cell changes both the book and the @@ -1171,7 +1176,7 @@ column being examined (the left-hand pane) - + Double-clicking in a cell changes both the book and the diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 9f58a2fa0d..d2a02da8b4 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -426,12 +426,14 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ if self.system_tray_icon is not None and self.system_tray_icon.isVisible() and opts.start_in_tray: self.hide_windows() self.auto_adder = AutoAdder(gprefs['auto_add_path'], self) - self.save_layout_state() - if gprefs['qv_show_on_startup']: - qv = find_plugin('Show Quickview') - if qv is not None: - qv.actual_plugin_.show_quickview() + # Now that the gui is initialized we can restore the quickview state + # The same thing will be true for any action-based operation with a + # layout button + qv = find_plugin('Show Quickview') + if qv is not None: + qv.actual_plugin_.qv_button.restore_state() + self.save_layout_state() # Collect cycles now gc.collect()