From 00e601624222cfaa98cd6d10912450f3b1361441 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 3 Nov 2010 14:37:50 -0600 Subject: [PATCH 1/3] Initial port to using QWebView to display comments in Book details pane --- src/calibre/gui2/book_details.py | 38 ++++++++++++++------------------ 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index cfb582024d..ec5f4ca731 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -7,9 +7,10 @@ __docformat__ = 'restructuredtext en' import os, collections -from PyQt4.Qt import QLabel, QPixmap, QSize, QWidget, Qt, pyqtSignal, \ +from PyQt4.Qt import QPixmap, QSize, QWidget, Qt, pyqtSignal, \ QVBoxLayout, QScrollArea, QPropertyAnimation, QEasingCurve, \ QSizePolicy, QPainter, QRect, pyqtProperty +from PyQt4.QtWebKit import QWebView from calibre import fit_image, prepare_string_for_xml from calibre.gui2.widgets import IMAGE_EXTENSIONS @@ -165,31 +166,26 @@ class CoverView(QWidget): # {{{ # }}} # Book Info {{{ -class Label(QLabel): +class InfoBook(QWebView): - mr = pyqtSignal(object) link_clicked = pyqtSignal(object) - def __init__(self): - QLabel.__init__(self) - self.setTextFormat(Qt.RichText) - self.setText('') - self.setWordWrap(True) - self.setAlignment(Qt.AlignTop) - self.linkActivated.connect(self.link_activated) + def __init__(self, parent): + QWebView.__init__(self, parent) + self.page().setLinkDelegationPolicy(self.page().DelegateAllLinks) + self.linkClicked.connect(self.link_activated) self._link_clicked = False self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + #self.loadFinished.connect(self.turnoff_scrollbar) def link_activated(self, link): self._link_clicked = True - link = unicode(link) + link = unicode(link.toString()) self.link_clicked.emit(link) - def mouseReleaseEvent(self, ev): - QLabel.mouseReleaseEvent(self, ev) - if not self._link_clicked: - self.mr.emit(ev) - self._link_clicked = False + def turnoff_scrollbar(self, *args): + self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) + class BookInfo(QScrollArea): @@ -197,14 +193,13 @@ class BookInfo(QScrollArea): QScrollArea.__init__(self, parent) self.vertical = vertical self.setWidgetResizable(True) - self.label = Label() + self.label = InfoView(self) self.setWidget(self.label) self.link_clicked = self.label.link_clicked - self.mr = self.label.mr self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) def show_data(self, data): - self.label.setText('') + self.label.setHtml('') rows = render_rows(data) rows = u'\n'.join([u'%s:%s'%(k,t) for k, t in rows]) @@ -215,11 +210,11 @@ class BookInfo(QScrollArea): if self.vertical: if comments: rows += u'%s'%comments - self.label.setText(u'%s
'%rows) + self.label.setHtml(u'%s
'%rows) else: left_pane = u'%s
'%rows right_pane = u'
%s
'%comments - self.label.setText(u'
%s%s
' % (left_pane, right_pane)) @@ -281,7 +276,6 @@ class BookDetails(QWidget): # {{{ self.book_info = BookInfo(vertical, self) self._layout.addWidget(self.book_info) self.book_info.link_clicked.connect(self._link_clicked) - self.book_info.mr.connect(self.mouseReleaseEvent) if vertical: self.setMinimumSize(QSize(190, 200)) else: From f7cef0df84662e066369c2eecbb9a95f18215199 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 3 Nov 2010 15:16:21 -0600 Subject: [PATCH 2/3] CLeanup qwebview layout --- src/calibre/gui2/book_details.py | 47 ++++++++++++-------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index ec5f4ca731..e2820c3dbf 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import os, collections from PyQt4.Qt import QPixmap, QSize, QWidget, Qt, pyqtSignal, \ - QVBoxLayout, QScrollArea, QPropertyAnimation, QEasingCurve, \ + QVBoxLayout, QPropertyAnimation, QEasingCurve, \ QSizePolicy, QPainter, QRect, pyqtProperty from PyQt4.QtWebKit import QWebView @@ -80,8 +80,9 @@ class CoverView(QWidget): # {{{ self.animation.setStartValue(QSize(0, 0)) self.animation.valueChanged.connect(self.value_changed) - self.setSizePolicy(QSizePolicy.Expanding if vertical else - QSizePolicy.Minimum, QSizePolicy.Expanding) + self.setSizePolicy( + QSizePolicy.Expanding if vertical else QSizePolicy.Minimum, + QSizePolicy.Minimum if vertical else QSizePolicy.Expanding) self.default_pixmap = QPixmap(I('book.png')) self.pixmap = self.default_pixmap @@ -110,10 +111,13 @@ class CoverView(QWidget): # {{{ self.current_pixmap_size = QSize(self.pwidth, self.pheight) self.animation.setEndValue(self.current_pixmap_size) + def sizeHint(self): + return self.maximumSize() + def relayout(self, parent_size): if self.vertical: - self.setMaximumSize(parent_size.width(), - min(int(parent_size.height()/2.),int(4/3. * parent_size.width())+1)) + mh = min(int(parent_size.height()/2.),int(4/3. * parent_size.width())+1) + self.setMaximumSize(parent_size.width(), mh) else: self.setMaximumSize(1+int(3/4. * parent_size.height()), parent_size.height()) @@ -121,9 +125,6 @@ class CoverView(QWidget): # {{{ self.animation.stop() self.do_layout() - def sizeHint(self): - return self.maximumSize() - def show_data(self, data): self.animation.stop() same_item = data.get('id', True) == self.data.get('id', False) @@ -166,17 +167,16 @@ class CoverView(QWidget): # {{{ # }}} # Book Info {{{ -class InfoBook(QWebView): +class BookInfo(QWebView): link_clicked = pyqtSignal(object) - def __init__(self, parent): + def __init__(self, vertical, parent=None): QWebView.__init__(self, parent) + self.vertical = vertical self.page().setLinkDelegationPolicy(self.page().DelegateAllLinks) self.linkClicked.connect(self.link_activated) self._link_clicked = False - self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - #self.loadFinished.connect(self.turnoff_scrollbar) def link_activated(self, link): self._link_clicked = True @@ -187,19 +187,8 @@ class InfoBook(QWebView): self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) -class BookInfo(QScrollArea): - - def __init__(self, vertical, parent=None): - QScrollArea.__init__(self, parent) - self.vertical = vertical - self.setWidgetResizable(True) - self.label = InfoView(self) - self.setWidget(self.label) - self.link_clicked = self.label.link_clicked - self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - def show_data(self, data): - self.label.setHtml('') + self.setHtml('') rows = render_rows(data) rows = u'\n'.join([u'%s:%s'%(k,t) for k, t in rows]) @@ -210,11 +199,11 @@ class BookInfo(QScrollArea): if self.vertical: if comments: rows += u'%s'%comments - self.label.setHtml(u'%s
'%rows) + self.setHtml(u'%s
'%rows) else: left_pane = u'%s
'%rows right_pane = u'
%s
'%comments - self.label.setHtml(u'
%s%s
' % (left_pane, right_pane)) @@ -270,7 +259,6 @@ class BookDetails(QWidget): # {{{ self.setLayout(self._layout) self.cover_view = CoverView(vertical, self) - self.cover_view.relayout(self.size()) self.resized.connect(self.cover_view.relayout, type=Qt.QueuedConnection) self._layout.addWidget(self.cover_view) self.book_info = BookInfo(vertical, self) @@ -298,11 +286,12 @@ class BookDetails(QWidget): # {{{ self.show_book_info.emit() def resizeEvent(self, ev): - self.resized.emit(self.size()) + sz = self.size() + self.resized.emit(sz) def show_data(self, data): - self.cover_view.show_data(data) self.book_info.show_data(data) + self.cover_view.show_data(data) self.setToolTip('

'+_('Click to open Book Details window') + '

' + _('Path') + ': ' + data.get(_('Path'), '')) From ef16f448369db3396e3d7b427f5eae92cd377597 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 3 Nov 2010 17:07:50 -0600 Subject: [PATCH 3/3] Use a custom layout to layout the book details pane. Also switch to double click to open book details dialog --- src/calibre/gui2/book_details.py | 134 ++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 37 deletions(-) diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index e2820c3dbf..b9c01a1b87 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -8,8 +8,8 @@ __docformat__ = 'restructuredtext en' import os, collections from PyQt4.Qt import QPixmap, QSize, QWidget, Qt, pyqtSignal, \ - QVBoxLayout, QPropertyAnimation, QEasingCurve, \ - QSizePolicy, QPainter, QRect, pyqtProperty + QPropertyAnimation, QEasingCurve, \ + QSizePolicy, QPainter, QRect, pyqtProperty, QLayout from PyQt4.QtWebKit import QWebView from calibre import fit_image, prepare_string_for_xml @@ -68,10 +68,7 @@ class CoverView(QWidget): # {{{ def __init__(self, vertical, parent=None): QWidget.__init__(self, parent) - self.setMaximumSize(QSize(120, 120)) - self.setMinimumSize(QSize(120 if vertical else 20, 120 if vertical else - 20)) - self._current_pixmap_size = self.maximumSize() + self._current_pixmap_size = QSize(120, 120) self.vertical = vertical self.animation = QPropertyAnimation(self, 'current_pixmap_size', self) @@ -82,7 +79,7 @@ class CoverView(QWidget): # {{{ self.setSizePolicy( QSizePolicy.Expanding if vertical else QSizePolicy.Minimum, - QSizePolicy.Minimum if vertical else QSizePolicy.Expanding) + QSizePolicy.Expanding) self.default_pixmap = QPixmap(I('book.png')) self.pixmap = self.default_pixmap @@ -111,20 +108,6 @@ class CoverView(QWidget): # {{{ self.current_pixmap_size = QSize(self.pwidth, self.pheight) self.animation.setEndValue(self.current_pixmap_size) - def sizeHint(self): - return self.maximumSize() - - def relayout(self, parent_size): - if self.vertical: - mh = min(int(parent_size.height()/2.),int(4/3. * parent_size.width())+1) - self.setMaximumSize(parent_size.width(), mh) - else: - self.setMaximumSize(1+int(3/4. * parent_size.height()), - parent_size.height()) - self.resize(self.maximumSize()) - self.animation.stop() - self.do_layout() - def show_data(self, data): self.animation.stop() same_item = data.get('id', True) == self.data.get('id', False) @@ -186,7 +169,6 @@ class BookInfo(QWebView): def turnoff_scrollbar(self, *args): self.page().mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) - def show_data(self, data): self.setHtml('') rows = render_rows(data) @@ -207,12 +189,100 @@ class BookInfo(QWebView): 'style="padding-right:2em">%s%s' % (left_pane, right_pane)) + def mouseDoubleClickEvent(self, ev): + ev.ignore() + +# }}} + + +class DetailsLayout(QLayout): # {{{ + + def __init__(self, vertical, parent): + QLayout.__init__(self, parent) + self.vertical = vertical + self._children = [] + + self.min_size = QSize(190, 200) if vertical else QSize(120, 120) + self.setContentsMargins(0, 0, 0, 0) + + def minimumSize(self): + return QSize(self.min_size) + + def addItem(self, child): + if len(self._children) > 2: + raise ValueError('This layout can only manage two children') + self._children.append(child) + + def itemAt(self, i): + try: + return self._children[i] + except: + pass + return None + + def takeAt(self, i): + try: + self._children.pop(i) + except: + pass + return None + + def count(self): + return len(self._children) + + def sizeHint(self): + return QSize(self.min_size) + + def setGeometry(self, r): + QLayout.setGeometry(self, r) + self.do_layout(r) + + def cover_height(self, r): + mh = min(int(r.height()/2.), int(4/3. * r.width())+1) + try: + ph = self._children[0].widget().pixmap.height() + except: + ph = 0 + if ph > 0: + mh = min(mh, ph) + return mh + + def cover_width(self, r): + mw = 1 + int(3/4. * r.height()) + try: + pw = self._children[0].widget().pixmap.width() + except: + pw = 0 + if pw > 0: + mw = min(mw, pw) + return mw + + + def do_layout(self, rect): + if len(self._children) != 2: + return + left, top, right, bottom = self.getContentsMargins() + r = rect.adjusted(+left, +top, -right, -bottom) + x = r.x() + y = r.y() + cover, details = self._children + if self.vertical: + ch = self.cover_height(r) + cover.setGeometry(QRect(x, y, r.width(), ch)) + cover.widget().do_layout() + y += ch + 5 + details.setGeometry(QRect(x, y, r.width(), r.height()-ch-5)) + else: + cw = self.cover_width(r) + cover.setGeometry(QRect(x, y, cw, r.height())) + cover.widget().do_layout() + x += cw + 5 + details.setGeometry(QRect(x, y, r.width() - cw - 5, r.height())) # }}} class BookDetails(QWidget): # {{{ - resized = pyqtSignal(object) show_book_info = pyqtSignal() open_containing_folder = pyqtSignal(int) view_specific_format = pyqtSignal(int, object) @@ -253,21 +323,14 @@ class BookDetails(QWidget): # {{{ def __init__(self, vertical, parent=None): QWidget.__init__(self, parent) self.setAcceptDrops(True) - self._layout = QVBoxLayout() - if not vertical: - self._layout.setDirection(self._layout.LeftToRight) + self._layout = DetailsLayout(vertical, self) self.setLayout(self._layout) self.cover_view = CoverView(vertical, self) - self.resized.connect(self.cover_view.relayout, type=Qt.QueuedConnection) self._layout.addWidget(self.cover_view) self.book_info = BookInfo(vertical, self) self._layout.addWidget(self.book_info) self.book_info.link_clicked.connect(self._link_clicked) - if vertical: - self.setMinimumSize(QSize(190, 200)) - else: - self.setMinimumSize(120, 120) self.setCursor(Qt.PointingHandCursor) def _link_clicked(self, link): @@ -281,18 +344,15 @@ class BookDetails(QWidget): # {{{ open_local_file(val) - def mouseReleaseEvent(self, ev): + def mouseDoubleClickEvent(self, ev): ev.accept() self.show_book_info.emit() - def resizeEvent(self, ev): - sz = self.size() - self.resized.emit(sz) - def show_data(self, data): self.book_info.show_data(data) self.cover_view.show_data(data) - self.setToolTip('

'+_('Click to open Book Details window') + + self._layout.do_layout(self.rect()) + self.setToolTip('

'+_('Double-click to open Book Details window') + '

' + _('Path') + ': ' + data.get(_('Path'), '')) def reset_info(self):