This commit is contained in:
Kovid Goyal 2011-04-07 22:51:05 -06:00
parent 638f70b640
commit 90a5a5ad41

View File

@ -8,6 +8,7 @@ __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
from threading import Thread, Event from threading import Thread, Event
from operator import attrgetter
from PyQt4.Qt import (QStyledItemDelegate, QTextDocument, QRectF, QIcon, Qt, from PyQt4.Qt import (QStyledItemDelegate, QTextDocument, QRectF, QIcon, Qt,
QStyle, QApplication, QDialog, QVBoxLayout, QLabel, QDialogButtonBox, QStyle, QApplication, QDialog, QVBoxLayout, QLabel, QDialogButtonBox,
@ -22,7 +23,7 @@ from calibre.ebooks.metadata.sources.identify import identify
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
from calibre.gui2 import error_dialog, NONE from calibre.gui2 import error_dialog, NONE
from calibre.utils.date import utcnow, fromordinal, format_date from calibre.utils.date import utcnow, fromordinal, format_date
from calibre.library.comments import comments_to_html
class RichTextDelegate(QStyledItemDelegate): # {{{ class RichTextDelegate(QStyledItemDelegate): # {{{
@ -107,10 +108,33 @@ class ResultsModel(QAbstractTableModel):
return self.yes_icon return self.yes_icon
if col == 4 and book.comments: if col == 4 and book.comments:
return self.yes_icon return self.yes_icon
elif role == Qt.UserRole:
return book
return NONE return NONE
def sort(self, col, order=Qt.AscendingOrder):
key = lambda x: x
if col == 0:
key = attrgetter('gui_rank')
elif col == 1:
key = attrgetter('title')
elif col == 2:
key = attrgetter('authors')
elif col == 3:
key = attrgetter('has_cached_cover_url')
elif key == 4:
key = lambda x: bool(x.comments)
self.results.sort(key=key, reverse=order==Qt.AscendingOrder)
self.reset()
class ResultsView(QTableView): # {{{ class ResultsView(QTableView): # {{{
show_details_signal = pyqtSignal(object)
book_selected = pyqtSignal(object)
def __init__(self, parent=None): def __init__(self, parent=None):
QTableView.__init__(self, parent) QTableView.__init__(self, parent)
self.rt_delegate = RichTextDelegate(self) self.rt_delegate = RichTextDelegate(self)
@ -118,6 +142,9 @@ class ResultsView(QTableView): # {{{
self.setAlternatingRowColors(True) self.setAlternatingRowColors(True)
self.setSelectionBehavior(self.SelectRows) self.setSelectionBehavior(self.SelectRows)
self.setIconSize(QSize(24, 24)) self.setIconSize(QSize(24, 24))
self.clicked.connect(self.show_details)
self.doubleClicked.connect(self.select_index)
self.setSortingEnabled(True)
def show_results(self, results): def show_results(self, results):
self._model = ResultsModel(results, self) self._model = ResultsModel(results, self)
@ -126,6 +153,38 @@ class ResultsView(QTableView): # {{{
self.setItemDelegateForColumn(i, self.rt_delegate) self.setItemDelegateForColumn(i, self.rt_delegate)
self.resizeRowsToContents() self.resizeRowsToContents()
self.resizeColumnsToContents() self.resizeColumnsToContents()
self.setFocus(Qt.OtherFocusReason)
def currentChanged(self, current, previous):
ret = QTableView.currentChanged(self, current, previous)
self.show_details(current)
return ret
def show_details(self, index):
book = self.model().data(index, Qt.UserRole)
parts = [
'<center>',
'<h2>%s</h2>'%book.title,
'<div><i>%s</i></div>'%authors_to_string(book.authors),
]
if not book.is_null('rating'):
parts.append('<div>%s</div>'%('\u2605'*int(book.rating)))
parts.append('</center>')
if book.tags:
parts.append('<div>%s</div><div>\u00a0</div>'%', '.join(book.tags))
if book.comments:
parts.append(comments_to_html(book.comments))
self.show_details_signal.emit(''.join(parts))
def select_index(self, index):
if not index.isValid():
index = self.model().index(0, 0)
book = self.model().data(index, Qt.UserRole)
self.book_selected.emit(book)
def get_result(self):
self.select_index(self.currentIndex())
# }}} # }}}
@ -224,6 +283,8 @@ class IdentifyWorker(Thread): # {{{
class IdentifyWidget(QWidget): # {{{ class IdentifyWidget(QWidget): # {{{
rejected = pyqtSignal() rejected = pyqtSignal()
results_found = pyqtSignal()
book_selected = pyqtSignal(object)
def __init__(self, log, parent=None): def __init__(self, log, parent=None):
QWidget.__init__(self, parent) QWidget.__init__(self, parent)
@ -241,11 +302,15 @@ class IdentifyWidget(QWidget): # {{{
l.addWidget(self.top, 0, 0) l.addWidget(self.top, 0, 0)
self.results_view = ResultsView(self) self.results_view = ResultsView(self)
self.results_view.book_selected.connect(self.book_selected.emit)
self.get_result = self.results_view.get_result
l.addWidget(self.results_view, 1, 0) l.addWidget(self.results_view, 1, 0)
self.comments_view = Comments(self) self.comments_view = Comments(self)
l.addWidget(self.comments_view, 1, 1) l.addWidget(self.comments_view, 1, 1)
self.results_view.show_details_signal.connect(self.comments_view.show_data)
self.query = QLabel('download starting...') self.query = QLabel('download starting...')
f = self.query.font() f = self.query.font()
f.setPointSize(f.pointSize()-2) f.setPointSize(f.pointSize()-2)
@ -326,6 +391,8 @@ class IdentifyWidget(QWidget): # {{{
<div>To see <b>details</b>, click on any result</div>''' % <div>To see <b>details</b>, click on any result</div>''' %
len(self.worker.results)) len(self.worker.results))
self.results_found.emit()
def cancel(self): def cancel(self):
self.abort.set() self.abort.set()
@ -345,23 +412,46 @@ class FullFetch(QDialog): # {{{
self.setLayout(l) self.setLayout(l)
l.addWidget(self.stack) l.addWidget(self.stack)
self.bb = QDialogButtonBox(QDialogButtonBox.Cancel) self.bb = QDialogButtonBox(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
l.addWidget(self.bb) l.addWidget(self.bb)
self.bb.rejected.connect(self.reject) self.bb.rejected.connect(self.reject)
self.next_button = self.bb.addButton(_('Next'), self.bb.AcceptRole)
self.next_button.setDefault(True)
self.next_button.setEnabled(False)
self.next_button.clicked.connect(self.next_clicked)
self.ok_button = self.bb.button(self.bb.Ok)
self.ok_button.setVisible(False)
self.ok_button.clicked.connect(self.ok_clicked)
self.identify_widget = IdentifyWidget(log, self) self.identify_widget = IdentifyWidget(log, self)
self.identify_widget.rejected.connect(self.reject) self.identify_widget.rejected.connect(self.reject)
self.identify_widget.results_found.connect(self.identify_results_found)
self.identify_widget.book_selected.connect(self.book_selected)
self.stack.addWidget(self.identify_widget) self.stack.addWidget(self.identify_widget)
self.resize(850, 500) self.resize(850, 500)
def book_selected(self, book):
print (book)
self.next_button.setVisible(False)
self.ok_button.setVisible(True)
def accept(self): def accept(self):
# Prevent pressing Enter from closing the dialog # Prevent the usual dialog accept mechanisms from working
pass pass
def reject(self): def reject(self):
self.identify_widget.cancel() self.identify_widget.cancel()
return QDialog.reject(self) return QDialog.reject(self)
def identify_results_found(self):
self.next_button.setEnabled(True)
def next_clicked(self, *args):
self.identify_widget.get_result()
def ok_clicked(self, *args):
pass
def start(self, title=None, authors=None, identifiers={}): def start(self, title=None, authors=None, identifiers={}):
self.identify_widget.start(title=title, authors=authors, self.identify_widget.start(title=title, authors=authors,
identifiers=identifiers) identifiers=identifiers)