Another attempt at enhancement #1415714. The user has the choice of putting quickview in its own window (original implementation) or as a splitter panel containing library view and the quickview panes.

This commit is contained in:
Charles Haley 2015-01-30 13:33:11 +01:00
parent 9e7d1a6ed4
commit f26495354f
4 changed files with 151 additions and 28 deletions

View File

@ -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):

View File

@ -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)

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -68,8 +68,33 @@
<string>&amp;Lock Quickview contents</string>
</property>
<property name="toolTip">
<string>Select to prevent Quickview from changing content when the
selection on the library view is changed</string>
<string>&lt;p&gt;Select to prevent Quickview from changing content when the
selection on the library view is changed&lt;/p&gt;</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="show_as_pane">
<property name="text">
<string>Sho&amp;w as pane</string>
</property>
<property name="toolTip">
<string>&lt;p&gt;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.&lt;/p&gt;</string>
</property>
</widget>
</item>

View File

@ -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): # {{{