diff --git a/src/calibre/gui2/actions/show_quickview.py b/src/calibre/gui2/actions/show_quickview.py index bc2dc82b0c..e6d693bb22 100644 --- a/src/calibre/gui2/actions/show_quickview.py +++ b/src/calibre/gui2/actions/show_quickview.py @@ -25,6 +25,7 @@ class ShowQuickviewAction(InterfaceAction): def show_quickview(self, *args): if self.current_instance: if not self.current_instance.is_closed: + self.current_instance.set_focus() return self.current_instance = None if self.gui.current_view() is not self.gui.library_view: @@ -34,8 +35,7 @@ class ShowQuickviewAction(InterfaceAction): return index = self.gui.library_view.currentIndex() if index.isValid(): - self.current_instance = \ - Quickview(self.gui, self.gui.library_view, index) + self.current_instance = Quickview(self.gui, index) self.current_instance.show() def change_quickview_column(self, idx): diff --git a/src/calibre/gui2/dialogs/quickview.py b/src/calibre/gui2/dialogs/quickview.py index 9df7200fbe..c795db7c88 100644 --- a/src/calibre/gui2/dialogs/quickview.py +++ b/src/calibre/gui2/dialogs/quickview.py @@ -5,8 +5,8 @@ __docformat__ = 'restructuredtext en' from PyQt5.Qt import (Qt, QDialog, QAbstractItemView, QTableWidgetItem, - QListWidgetItem, QByteArray, QCoreApplication, - QApplication, pyqtSignal, QDialogButtonBox) + QListWidgetItem, QCoreApplication, QEvent, QObject, + QApplication, pyqtSignal, QDialogButtonBox, QByteArray) from calibre.customize.ui import find_plugin from calibre.gui2 import gprefs @@ -42,33 +42,52 @@ class TableItem(QTableWidgetItem): return self.sort_idx < other.sort_idx return 0 +class KeyPressFilter(QObject): + + return_pressed_signal = pyqtSignal() + + def eventFilter(self, obj, event): + if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Return: + self.return_pressed_signal.emit() + return True; + else: + return QObject.eventFilter(self, obj, event); + class Quickview(QDialog, Ui_Quickview): change_quickview_column = pyqtSignal(object) - def __init__(self, gui, view, row): - QDialog.__init__(self, gui, flags=Qt.Window) + 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) + else: + QDialog.__init__(self, gui) Ui_Quickview.__init__(self) self.setupUi(self) self.isClosed = False + self.books_table_column_widths = None try: self.books_table_column_widths = \ gprefs.get('quickview_dialog_books_table_widths', None) - geom = gprefs.get('quickview_dialog_geometry', bytearray('')) - self.restoreGeometry(QByteArray(geom)) + if not self.is_pane: + geom = gprefs.get('quickview_dialog_geometry', bytearray('')) + self.restoreGeometry(QByteArray(geom)) except: pass - # Remove the help button from the window title bar - icon = self.windowIcon() - self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint)) - self.setWindowFlags(self.windowFlags()|Qt.WindowStaysOnTopHint) - self.setWindowIcon(icon) + if not self.is_pane: + # Remove the help button from the window title bar + icon = self.windowIcon() + self.setWindowFlags(self.windowFlags()&(~Qt.WindowContextHelpButtonHint)) + self.setWindowFlags(self.windowFlags()|Qt.WindowStaysOnTopHint) + self.setWindowIcon(icon) - self.db = view.model().db - self.view = view + self.view = gui.library_view + self.db = self.view.model().db self.gui = gui self.is_closed = False self.current_book_id = None @@ -89,6 +108,9 @@ class Quickview(QDialog, Ui_Quickview): self.items.currentTextChanged.connect(self.item_selected) # Set up the books table columns + return_filter = KeyPressFilter(self.books_table) + return_filter.return_pressed_signal.connect(self.return_pressed) + self.books_table.installEventFilter(return_filter) self.books_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.books_table.setSelectionMode(QAbstractItemView.SingleSelection) self.books_table.setColumnCount(3) @@ -118,10 +140,28 @@ class Quickview(QDialog, Ui_Quickview): self.change_quickview_column.connect(self.slave) QCoreApplication.instance().aboutToQuit.connect(self.save_state) self.search_button.clicked.connect(self.do_search) - view.model().new_bookdisplay_data.connect(self.book_was_changed) + self.view.model().new_bookdisplay_data.connect(self.book_was_changed) close_button = self.buttonBox.button(QDialogButtonBox.Close) - close_button.setAutoDefault(False) + close_button.setDefault(False) + if self.is_pane: + close_button.setText(_('&Close')) + + self.books_table.horizontalHeader().sectionResized.connect(self.section_resized) + if self.is_pane: + self.gui.quickview_splitter.add_quickview_dialog(self) + self.set_focus() + + self.show_as_pane.setChecked(self.is_pane) + self.show_as_pane.stateChanged.connect(self.show_as_pane_changed) + + def show(self): + QDialog.show(self) + if self.is_pane: + self.gui.quickview_splitter.show_quickview_widget() + + def show_as_pane_changed(self, new_state): + gprefs['quickview_is_pane'] = self.show_as_pane.isChecked() # search button def do_search(self): @@ -261,6 +301,11 @@ class Quickview(QDialog, Ui_Quickview): # correct until the first paint. def resizeEvent(self, *args): QDialog.resizeEvent(self, *args) + + # Do this if we are resizing for the first time to reset state. + if self.is_pane and self.height() == 0: + self.gui.quickview_splitter.set_sizes() + if self.books_table_column_widths is not None: for c,w in enumerate(self.books_table_column_widths): self.books_table.setColumnWidth(c, w) @@ -274,9 +319,15 @@ class Quickview(QDialog, Ui_Quickview): self.books_table.setColumnWidth(c, w) self.save_state() + def return_pressed(self): + self.select_book(self.books_table.currentRow()) + def book_doubleclicked(self, row, column): if self.no_valid_items: return + self.select_book(row) + + def select_book(self, row): book_id = int(self.books_table.item(row, self.title_column).data(Qt.UserRole)) self.view.select_rows([book_id]) modifiers = int(QApplication.keyboardModifiers()) @@ -285,6 +336,9 @@ class Quickview(QDialog, Ui_Quickview): if em is not None: em.actual_plugin_.edit_metadata(None) + def set_focus(self): + self.books_table.setFocus(Qt.ActiveWindowFocusReason) + # called when a book is clicked on the library view def slave(self, current): if self.is_closed: @@ -292,6 +346,9 @@ class Quickview(QDialog, Ui_Quickview): self.refresh(current) self.view.activateWindow() + def section_resized(self, logicalIndex, oldSize, newSize): + self.save_state() + def save_state(self): if self.is_closed: return @@ -299,7 +356,8 @@ class Quickview(QDialog, Ui_Quickview): for c in range(0, self.books_table.columnCount()): self.books_table_column_widths.append(self.books_table.columnWidth(c)) gprefs['quickview_dialog_books_table_widths'] = self.books_table_column_widths - gprefs['quickview_dialog_geometry'] = bytearray(self.saveGeometry()) + if not self.is_pane: + gprefs['quickview_dialog_geometry'] = bytearray(self.saveGeometry()) def _close(self): self.save_state() @@ -307,12 +365,10 @@ class Quickview(QDialog, Ui_Quickview): self.db = self.view = self.gui = None self.is_closed = True - # called by the window system - def closeEvent(self, *args): - self._close() - QDialog.closeEvent(self, *args) - # called by the close button def reject(self): + if self.is_pane: + self.gui.quickview_splitter.hide_quickview_widget() + self.gui.library_view.setFocus(Qt.ActiveWindowFocusReason) self._close() QDialog.reject(self) diff --git a/src/calibre/gui2/dialogs/quickview.ui b/src/calibre/gui2/dialogs/quickview.ui index 3bd909288f..627b840d00 100644 --- a/src/calibre/gui2/dialogs/quickview.ui +++ b/src/calibre/gui2/dialogs/quickview.ui @@ -11,7 +11,7 @@ - + 0 0 @@ -68,8 +68,33 @@ &Lock Quickview contents - Select to prevent Quickview from changing content when the - selection on the library view is changed + <p>Select to prevent Quickview from changing content when the + selection on the library view is changed</p> + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + Sho&w as pane + + + <p>If checked, the next time Quickview is opened it will be shown + as a pane under the library view. If unchecked it will be shown as a + separate window.</p> diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 840c4c5ab8..f84df9d587 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -8,7 +8,8 @@ __docformat__ = 'restructuredtext en' import functools from PyQt5.Qt import (Qt, QApplication, QStackedWidget, QMenu, QTimer, - QSize, QSizePolicy, QStatusBar, QLabel, QFont, QAction, QTabBar) + QSize, QSizePolicy, QStatusBar, QLabel, QFont, QAction, QTabBar, + QVBoxLayout, QWidget, QSplitter) from calibre.utils.config import prefs from calibre.utils.icu import sort_key @@ -99,6 +100,37 @@ class LibraryViewMixin(object): # {{{ # }}} +class QuickviewSplitter(QSplitter): # {{{ + + def __init__(self, parent=None, orientation=Qt.Vertical, qv_widget=None): + QSplitter.__init__(self, parent=parent, orientation=orientation) + self.splitterMoved.connect(self.splitter_moved) + self.setChildrenCollapsible(False) + self.qv_widget = qv_widget + + def splitter_moved(self): + gprefs['quickview_dialog_heights'] = self.sizes() + + def resizeEvent(self, *args): + QSplitter.resizeEvent(self, *args) + if self.sizes()[1] != 0: + gprefs['quickview_dialog_heights'] = self.sizes() + + def set_sizes(self): + sizes = gprefs.get('quickview_dialog_heights', []) + if len(sizes) == 2: + self.setSizes(sizes) + + def add_quickview_dialog(self, qv_dialog): + self.qv_widget.layout().addWidget(qv_dialog) + + def show_quickview_widget(self): + self.qv_widget.show() + + def hide_quickview_widget(self): + self.qv_widget.hide() +# }}} + class LibraryWidget(Splitter): # {{{ def __init__(self, parent): @@ -113,6 +145,10 @@ class LibraryWidget(Splitter): # {{{ connect_button=not config['separate_cover_flow'], side_index=idx, initial_side_size=size, initial_show=False, shortcut='Shift+Alt+B') + + quickview_widget = QWidget() + parent.quickview_splitter = QuickviewSplitter( + parent=self, orientation=Qt.Vertical, qv_widget=quickview_widget) parent.library_view = BooksView(parent) parent.library_view.setObjectName('library_view') stack = QStackedWidget(self) @@ -121,7 +157,13 @@ class LibraryWidget(Splitter): # {{{ parent.grid_view = GridView(parent) parent.grid_view.setObjectName('grid_view') av.add_view('grid', parent.grid_view) - self.addWidget(stack) + parent.quickview_splitter.addWidget(stack) + + quickview_widget.setLayout(QVBoxLayout()) + parent.quickview_splitter.addWidget(quickview_widget) + parent.quickview_splitter.hide_quickview_widget() + + self.addWidget(parent.quickview_splitter) # }}} class Stack(QStackedWidget): # {{{