diff --git a/resources/images/devices/folder.svg b/resources/images/devices/folder.svg
index 74c1d628e4..e0d6f6b8be 100644
--- a/resources/images/devices/folder.svg
+++ b/resources/images/devices/folder.svg
@@ -9,544 +9,700 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- version="1.0"
- x="0.0000000"
- y="0.0000000"
- width="48.000000px"
- height="48.000000px"
- id="svg1"
+ width="128"
+ height="128"
+ id="svg2811"
sodipodi:version="0.32"
- inkscape:version="0.44"
- sodipodi:docname="folder.svg"
- sodipodi:docbase="/home/lapo/Icone/Crux/crux-icon-theme/scalable/places"
- inkscape:export-filename="/home/lapo/Icone/Crux/folderx-daritaliare.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ inkscape:version="0.45.1"
+ version="1.0"
+ sodipodi:docname="folder-downloads.svgz"
+ inkscape:output_extension="org.inkscape.output.svgz.inkscape"
+ inkscape:export-filename="folder-downloads.png"
+ inkscape:export-xdpi="11.25"
+ inkscape:export-ydpi="11.25"
+ sodipodi:docbase="/home/david/oxygen/trunk/scalable/places">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id="metadata2816">
image/svg+xml
- Folder
-
-
- Lapo Calamandrei
-
-
- 2006-06-26
-
-
-
-
- folder
- directory
- storage
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ id="layer1">
+
-
+ id="g17"
+ style="opacity:0.6;filter:url(#filter2807)"
+ transform="matrix(1.0033404,0,0,1,-8.2374684,8)">
-
+ d="M 132,96 C 132,98.2 128.4,100 124,100 L 20,100 C 15.6,100 12,98.2 12,96 C 12,93.8 15.6,92 20,92 L 124,92 C 128.4,92 132,93.8 132,96 z"
+ id="path19" />
+
+
+
+
+
+ id="g2450"
+ inkscape:label="Livello 1"
+ transform="translate(-2.4797995e-7,16)">
-
-
-
-
-
-
-
-
-
+ d="M 88,103.99999 C 88,106.20914 77.254827,108 63.999997,108 C 50.745166,108 40,106.20914 40,103.99999 C 40,101.79086 50.745166,100 63.999997,100 C 77.254827,100 88,101.79086 88,103.99999 L 88,103.99999 z "
+ style="opacity:0.3;fill:url(#radialGradient4545);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
+ id="path4543" />
+ transform="matrix(1,0,0,0.9756098,-72.426501,80.585366)"
+ id="g9589">
+ style="fill:url(#linearGradient9614)"
+ d="M 122.40803,-58 C 121.11995,-58 120.07225,-56.801009 120.07225,-55.327765 C 120.07225,-55.327765 120.07225,-20.243475 120.07225,-17.752469 C 118.07565,-17.752469 105.76289,-17.752469 105.76289,-17.752469 C 104.82364,-17.752469 103.98018,-17.113701 103.61327,-16.125567 C 103.61266,-16.122801 103.4265,-15.080231 103.4265,-15.080231 C 103.4265,-14.384954 103.65845,-13.726198 104.08019,-13.22662 L 134.74308,23.18138 C 135.18048,23.70094 135.7944,24 136.42579,24 C 137.05778,24 137.6705,23.70094 138.1085,23.18138 L 168.772,-13.22662 C 169.42327,-14.000449 169.60703,-15.136741 169.23953,-16.125567 C 168.87081,-17.115074 168.02735,-17.751777 167.08929,-17.751777 C 167.08929,-17.751777 154.77654,-17.751777 152.77994,-17.751777 C 152.77994,-20.243475 152.77994,-55.327076 152.77994,-55.327076 C 152.77933,-56.801009 151.73164,-58 150.44355,-58 L 122.40803,-58 z "
+ id="path49" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ style="opacity:0.5;fill:#ffffff"
+ enable-background="new "
+ d="M 152.77933,-15.331057 C 154.77534,-15.331057 167.08869,-15.331057 167.08869,-15.331057 C 168.02794,-15.331057 168.87021,-14.692971 169.23832,-13.704155 C 169.2594,-13.646273 169.27387,-13.585625 169.29193,-13.527062 C 169.48051,-14.144468 169.47147,-14.830788 169.23832,-15.457162 C 168.87021,-16.445977 168.02614,-17.084064 167.08869,-17.084064 C 167.08869,-17.084064 154.77534,-17.084064 152.77933,-17.084064 C 152.77933,-16.201364 152.77933,-15.589458 152.77933,-15.331057 z "
+ id="path74" />
+
+
+
+
+
+
+
+
diff --git a/resources/images/user_profile.svg b/resources/images/user_profile.svg
index 2fc0eea150..0aecc0c1f7 100644
--- a/resources/images/user_profile.svg
+++ b/resources/images/user_profile.svg
@@ -1,6 +1,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="im-user.svgz"
+ inkscape:output_extension="org.inkscape.output.svgz.inkscape"
+ sodipodi:docbase="/home/pinheiro/pics/oxygen/scalable/mimetypes"
+ inkscape:export-filename="/home/pinheiro/pics/oxygen/scalable/actions/im-user.png"
+ inkscape:export-xdpi="180"
+ inkscape:export-ydpi="180">
+ inkscape:current-layer="layer1"
+ width="128px"
+ height="128px"
+ showgrid="false"
+ inkscape:grid-points="true"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1016"
+ inkscape:window-height="692"
+ inkscape:window-x="20"
+ inkscape:window-y="356">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id="metadata2611">
image/svg+xml
-
-
-
- Jakub Steiner
-
-
- http://jimmac.musichall.cz
-
-
- user
- person
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ inkscape:label="Livello 1">
+ style="fill:#493a3a;fill-opacity:1;stroke:none;stroke-width:3.1559999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter3766)"
+ id="path3716"
+ sodipodi:cx="63.865829"
+ sodipodi:cy="108.4109"
+ sodipodi:rx="41.861637"
+ sodipodi:ry="13.953878"
+ d="M 105.72747,108.4109 A 41.861637,13.953878 0 1 1 22.004192,108.4109 A 41.861637,13.953878 0 1 1 105.72747,108.4109 z"
+ transform="matrix(0.8610583,0,0,1.1808092,8.9931858,-19.441249)" />
+
+
+
+
+
+
+
+
+ style="fill:url(#radialGradient4322);fill-opacity:1;stroke:none;stroke-width:3.40000010000000019;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path2563"
+ sodipodi:cx="58.041332"
+ sodipodi:cy="37.27911"
+ sodipodi:rx="29.958668"
+ sodipodi:ry="29.958668"
+ d="M 88,37.27911 A 29.958668,29.958668 0 1 1 28.082664,37.27911 A 29.958668,29.958668 0 1 1 88,37.27911 z"
+ transform="matrix(0.844028,0,0,0.844028,14.927656,-4.6758122)" />
+
+
+
+
+
+
diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index ca93990420..ec895cb8a4 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -436,7 +436,7 @@ from calibre.devices.blackberry.driver import BLACKBERRY
from calibre.devices.cybook.driver import CYBOOK
from calibre.devices.eb600.driver import EB600, COOL_ER, SHINEBOOK, \
POCKETBOOK360, GER2, ITALICA, ECLICTO, DBOOK, INVESBOOK, \
- BOOQ, ELONEX
+ BOOQ, ELONEX, POCKETBOOK301
from calibre.devices.iliad.driver import ILIAD
from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800
from calibre.devices.jetbook.driver import JETBOOK
@@ -507,6 +507,7 @@ plugins += [
JETBOOK,
SHINEBOOK,
POCKETBOOK360,
+ POCKETBOOK301,
KINDLE,
KINDLE2,
KINDLE_DX,
diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py
index 307531c357..9b7a21a3bb 100644
--- a/src/calibre/devices/eb600/driver.py
+++ b/src/calibre/devices/eb600/driver.py
@@ -201,4 +201,21 @@ class ELONEX(EB600):
def can_handle(cls, dev, debug=False):
return dev[3] == 'Elonex' and dev[4] == 'eBook'
+class POCKETBOOK301(USBMS):
+
+ name = 'PocketBook 301 Device Interface'
+ description = _('Communicate with the PocketBook 301 reader.')
+ author = 'Kovid Goyal'
+ supported_platforms = ['windows', 'osx', 'linux']
+ FORMATS = ['epub', 'fb2', 'prc', 'mobi', 'pdf', 'djvu', 'rtf', 'chm', 'txt']
+
+ SUPPORTS_SUB_DIRS = True
+
+ MAIN_MEMORY_VOLUME_LABEL = 'PocketBook 301 Main Memory'
+ STORAGE_CARD_VOLUME_LABEL = 'PocketBook 301 Storage Card'
+
+ VENDOR_ID = [0x1]
+ PRODUCT_ID = [0x301]
+ BCD = [0x132]
+
diff --git a/src/calibre/ebooks/epub/output.py b/src/calibre/ebooks/epub/output.py
index ee779aaefa..8708b98d97 100644
--- a/src/calibre/ebooks/epub/output.py
+++ b/src/calibre/ebooks/epub/output.py
@@ -385,14 +385,6 @@ class EPUBOutput(OutputFormatPlugin):
if val and not pval:
rule.style.setProperty('padding-left', val)
- if stylesheet is not None:
- stylesheet.data.add('a { color: inherit; text-decoration: inherit; '
- 'cursor: default; }')
- stylesheet.data.add('a[href] { color: blue; '
- 'text-decoration: underline; cursor:pointer; }')
- else:
- self.oeb.log.warn('No stylesheet found')
-
# }}}
def workaround_sony_quirks(self): # {{{
diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py
index a397ab903d..8759dd360b 100644
--- a/src/calibre/gui2/book_details.py
+++ b/src/calibre/gui2/book_details.py
@@ -62,11 +62,13 @@ def render_rows(data):
class CoverView(QWidget): # {{{
- def __init__(self, parent=None):
+ def __init__(self, vertical, parent=None):
QWidget.__init__(self, parent)
self.setMaximumSize(QSize(120, 120))
- self.setMinimumSize(QSize(120, 1))
+ self.setMinimumSize(QSize(120 if vertical else 20, 120 if vertical else
+ 20))
self._current_pixmap_size = self.maximumSize()
+ self.vertical = vertical
self.animation = QPropertyAnimation(self, 'current_pixmap_size', self)
self.animation.setEasingCurve(QEasingCurve(QEasingCurve.OutExpo))
@@ -74,7 +76,8 @@ class CoverView(QWidget): # {{{
self.animation.setStartValue(QSize(0, 0))
self.animation.valueChanged.connect(self.value_changed)
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+ self.setSizePolicy(QSizePolicy.Expanding if vertical else
+ QSizePolicy.Minimum, QSizePolicy.Expanding)
self.default_pixmap = QPixmap(I('book.svg'))
self.pixmap = self.default_pixmap
@@ -98,8 +101,12 @@ class CoverView(QWidget): # {{{
self.animation.setEndValue(self.current_pixmap_size)
def relayout(self, parent_size):
- self.setMaximumSize(parent_size.width(),
- min(int(parent_size.height()/2.),int(4/3. * parent_size.width())+1))
+ if self.vertical:
+ self.setMaximumSize(parent_size.width(),
+ min(int(parent_size.height()/2.),int(4/3. * parent_size.width())+1))
+ else:
+ self.setMaximumSize(1+int(3/4. * parent_size.height()),
+ parent_size.height())
self.resize(self.maximumSize())
self.animation.stop()
self.do_layout()
@@ -109,8 +116,7 @@ class CoverView(QWidget): # {{{
def show_data(self, data):
self.animation.stop()
- if data.get('id', True) == self.data.get('id', False):
- return
+ same_item = data.get('id', True) == self.data.get('id', False)
self.data = {'id':data.get('id', None)}
if data.has_key('cover'):
self.pixmap = QPixmap.fromImage(data.pop('cover'))
@@ -120,7 +126,8 @@ class CoverView(QWidget): # {{{
self.pixmap = self.default_pixmap
self.do_layout()
self.update()
- self.animation.start()
+ if not same_item:
+ self.animation.start()
def paintEvent(self, event):
canvas_size = self.rect()
@@ -147,6 +154,7 @@ class CoverView(QWidget): # {{{
# }}}
+# Book Info {{{
class Label(QLabel):
mr = pyqtSignal(object)
@@ -174,8 +182,9 @@ class Label(QLabel):
class BookInfo(QScrollArea):
- def __init__(self, parent=None):
+ def __init__(self, vertical, parent=None):
QScrollArea.__init__(self, parent)
+ self.vertical = vertical
self.setWidgetResizable(True)
self.label = Label()
self.setWidget(self.label)
@@ -188,13 +197,25 @@ class BookInfo(QScrollArea):
rows = render_rows(data)
rows = u'\n'.join([u'
%s: %s '%(k,t) for
k, t in rows])
- if _('Comments') in data and data[_('Comments')]:
- comments = comments_to_html(data[_('Comments')])
- rows += u'%s '%comments
+ if self.vertical:
+ if _('Comments') in data and data[_('Comments')]:
+ comments = comments_to_html(data[_('Comments')])
+ rows += u'%s '%comments
+ self.label.setText(u''%rows)
+ else:
+ comments = ''
+ if _('Comments') in data:
+ comments = comments_to_html(data[_('Comments')])
+ left_pane = u''%rows
+ right_pane = u'%s
'%comments
+ self.label.setText(u''
+ % (left_pane, right_pane))
- self.label.setText(u''%rows)
-class BookDetails(QWidget):
+# }}}
+
+class BookDetails(QWidget): # {{{
resized = pyqtSignal(object)
show_book_info = pyqtSignal()
@@ -234,20 +255,26 @@ class BookDetails(QWidget):
# }}}
- def __init__(self, parent=None):
+ 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.setLayout(self._layout)
- self.cover_view = CoverView(self)
+
+ 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, alignment=Qt.AlignHCenter)
- self.book_info = BookInfo(self)
+ 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)
self.book_info.mr.connect(self.mouseReleaseEvent)
- self.setMinimumSize(QSize(190, 200))
+ if vertical:
+ self.setMinimumSize(QSize(190, 200))
+ else:
+ self.setMinimumSize(120, 120)
self.setCursor(Qt.PointingHandCursor)
def _link_clicked(self, link):
@@ -277,5 +304,5 @@ class BookDetails(QWidget):
def reset_info(self):
self.show_data({})
-
+# }}}
diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui
index ba92c0d301..efda00fc97 100644
--- a/src/calibre/gui2/dialogs/config/config.ui
+++ b/src/calibre/gui2/dialogs/config/config.ui
@@ -7,7 +7,7 @@
0
0
- 884
+ 1000
730
@@ -89,7 +89,7 @@
0
0
- 604
+ 720
679
@@ -370,7 +370,7 @@
- -
+
-
Show &average ratings in the tags browser
diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py
index 1277cb06c7..0a82d3b75b 100644
--- a/src/calibre/gui2/init.py
+++ b/src/calibre/gui2/init.py
@@ -8,17 +8,18 @@ __docformat__ = 'restructuredtext en'
import functools
from PyQt4.Qt import QMenu, Qt, pyqtSignal, QToolButton, QIcon, QStackedWidget, \
- QWidget, QHBoxLayout, QToolBar, QSize, QSizePolicy
+ QSize, QSizePolicy, QStatusBar
from calibre.utils.config import prefs
from calibre.ebooks import BOOK_EXTENSIONS
-from calibre.constants import isosx, __appname__
+from calibre.constants import isosx, __appname__, preferred_encoding
from calibre.gui2 import config, is_widescreen
from calibre.gui2.library.views import BooksView, DeviceBooksView
from calibre.gui2.widgets import Splitter
from calibre.gui2.tag_view import TagBrowserWidget
-from calibre.gui2.status import StatusBar, HStatusBar
from calibre.gui2.book_details import BookDetails
+from calibre.gui2.notify import get_notifier
+
_keep_refs = []
@@ -332,26 +333,24 @@ class Stack(QStackedWidget): # {{{
# }}}
-class SideBar(QToolBar): # {{{
+class StatusBar(QStatusBar): # {{{
+ def initialize(self, systray=None):
+ self.systray = systray
+ self.notifier = get_notifier(systray)
- def __init__(self, splitters, jobs_button, parent=None):
- QToolBar.__init__(self, _('Side bar'), parent)
- self.setOrientation(Qt.Vertical)
- self.setMovable(False)
- self.setFloatable(False)
- self.setToolButtonStyle(Qt.ToolButtonIconOnly)
- self.setIconSize(QSize(48, 48))
- self.spacer = QWidget(self)
- self.spacer.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
- for s in splitters:
- self.addWidget(s.button)
- self.addWidget(self.spacer)
- self.addWidget(jobs_button)
+ def show_message(self, msg, timeout=0):
+ QStatusBar.showMessage(self, msg, timeout)
+ if self.notifier is not None and not config['disable_tray_notification']:
+ if isosx and isinstance(msg, unicode):
+ try:
+ msg = msg.encode(preferred_encoding)
+ except UnicodeEncodeError:
+ msg = msg.encode('utf-8')
+ self.notifier(msg)
- for ch in self.children():
- if isinstance(ch, QToolButton):
- ch.setCursor(Qt.PointingHandCursor)
+ def clear_message(self):
+ QStatusBar.clearMessage(self)
# }}}
@@ -361,45 +360,46 @@ class LayoutMixin(object): # {{{
self.setupUi(self)
self.setWindowTitle(__appname__)
- if config['gui_layout'] == 'narrow':
- self.status_bar = self.book_details = StatusBar(self)
+ if config['gui_layout'] == 'narrow': # narrow {{{
+ self.book_details = BookDetails(False, self)
self.stack = Stack(self)
self.bd_splitter = Splitter('book_details_splitter',
_('Book Details'), I('book.svg'),
orientation=Qt.Vertical, parent=self, side_index=1)
- self._layout_mem = [QWidget(self), QHBoxLayout()]
- self._layout_mem[0].setLayout(self._layout_mem[1])
- l = self._layout_mem[1]
- l.addWidget(self.stack)
- self.sidebar = SideBar([getattr(self, x+'_splitter')
- for x in ('bd', 'tb', 'cb')], self.jobs_button, parent=self)
- l.addWidget(self.sidebar)
- self.bd_splitter.addWidget(self._layout_mem[0])
- self.bd_splitter.addWidget(self.status_bar)
+ self.bd_splitter.addWidget(self.stack)
+ self.bd_splitter.addWidget(self.book_details)
self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False)
self.centralwidget.layout().addWidget(self.bd_splitter)
- else:
- self.status_bar = HStatusBar(self)
- self.setStatusBar(self.status_bar)
+ # }}}
+ else: # wide {{{
self.bd_splitter = Splitter('book_details_splitter',
_('Book Details'), I('book.svg'), initial_side_size=200,
orientation=Qt.Horizontal, parent=self, side_index=1)
self.stack = Stack(self)
self.bd_splitter.addWidget(self.stack)
- self.book_details = BookDetails(self)
+ self.book_details = BookDetails(True, self)
self.bd_splitter.addWidget(self.book_details)
self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False)
self.bd_splitter.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,
QSizePolicy.Expanding))
self.centralwidget.layout().addWidget(self.bd_splitter)
+ # }}}
- for x in ('cb', 'tb', 'bd'):
- button = getattr(self, x+'_splitter').button
- button.setIconSize(QSize(22, 22))
- self.status_bar.addPermanentWidget(button)
- self.status_bar.addPermanentWidget(self.jobs_button)
+ self.status_bar = StatusBar(self)
+ for x in ('cb', 'tb', 'bd'):
+ button = getattr(self, x+'_splitter').button
+ button.setIconSize(QSize(24, 24))
+ self.status_bar.addPermanentWidget(button)
+ self.status_bar.addPermanentWidget(self.jobs_button)
+ self.setStatusBar(self.status_bar)
def finalize_layout(self):
+ self.status_bar.initialize(self.system_tray_icon)
+ self.book_details.show_book_info.connect(self.show_book_info)
+ self.book_details.files_dropped.connect(self.files_dropped_on_book)
+ self.book_details.open_containing_folder.connect(self.view_folder_for_id)
+ self.book_details.view_specific_format.connect(self.view_format_by_id)
+
m = self.library_view.model()
if m.rowCount(None) > 0:
self.library_view.set_current_row(0)
diff --git a/src/calibre/gui2/status.py b/src/calibre/gui2/status.py
deleted file mode 100644
index 9aa9b8262c..0000000000
--- a/src/calibre/gui2/status.py
+++ /dev/null
@@ -1,253 +0,0 @@
-__license__ = 'GPL v3'
-__copyright__ = '2008, Kovid Goyal '
-
-import os
-
-from PyQt4.Qt import QStatusBar, QLabel, QWidget, QHBoxLayout, QPixmap, \
- QSizePolicy, QScrollArea, Qt, QSize, pyqtSignal, \
- QPropertyAnimation, QEasingCurve, QDesktopServices, QUrl
-
-
-from calibre import fit_image, preferred_encoding, isosx
-from calibre.gui2 import config
-from calibre.gui2.widgets import IMAGE_EXTENSIONS
-from calibre.gui2.notify import get_notifier
-from calibre.ebooks import BOOK_EXTENSIONS
-from calibre.library.comments import comments_to_html
-from calibre.gui2.book_details import render_rows
-
-class BookInfoDisplay(QWidget):
-
- DROPABBLE_EXTENSIONS = IMAGE_EXTENSIONS+BOOK_EXTENSIONS
- files_dropped = pyqtSignal(object, object)
-
- @classmethod
- def paths_from_event(cls, event):
- '''
- Accept a drop event and return a list of paths that can be read from
- and represent files with extensions.
- '''
- if event.mimeData().hasFormat('text/uri-list'):
- urls = [unicode(u.toLocalFile()) for u in event.mimeData().urls()]
- urls = [u for u in urls if os.path.splitext(u)[1] and os.access(u, os.R_OK)]
- return [u for u in urls if os.path.splitext(u)[1][1:].lower() in cls.DROPABBLE_EXTENSIONS]
-
- def dragEnterEvent(self, event):
- if int(event.possibleActions() & Qt.CopyAction) + \
- int(event.possibleActions() & Qt.MoveAction) == 0:
- return
- paths = self.paths_from_event(event)
- if paths:
- event.acceptProposedAction()
-
- def dropEvent(self, event):
- paths = self.paths_from_event(event)
- event.setDropAction(Qt.CopyAction)
- self.files_dropped.emit(event, paths)
-
- def dragMoveEvent(self, event):
- event.acceptProposedAction()
-
-
- class BookCoverDisplay(QLabel): # {{{
-
- def __init__(self, coverpath=I('book.svg')):
- QLabel.__init__(self)
- self.animation = QPropertyAnimation(self, 'size', self)
- self.animation.setEasingCurve(QEasingCurve(QEasingCurve.OutExpo))
- self.animation.setDuration(1000)
- self.animation.setStartValue(QSize(0, 0))
- self.setMaximumWidth(81)
- self.setMaximumHeight(108)
- self.default_pixmap = QPixmap(coverpath)
- self.setScaledContents(True)
- self.statusbar_height = 120
- self.setPixmap(self.default_pixmap)
-
- def do_layout(self):
- self.animation.stop()
- pixmap = self.pixmap()
- pwidth, pheight = pixmap.width(), pixmap.height()
- width, height = fit_image(pwidth, pheight,
- pwidth, self.statusbar_height-20)[1:]
- self.setMaximumHeight(height)
- try:
- aspect_ratio = pwidth/float(pheight)
- except ZeroDivisionError:
- aspect_ratio = 1
- self.setMaximumWidth(int(aspect_ratio*self.maximumHeight()))
- self.animation.setEndValue(self.maximumSize())
-
- def setPixmap(self, pixmap):
- QLabel.setPixmap(self, pixmap)
- self.do_layout()
- self.animation.start()
-
- def sizeHint(self):
- return QSize(self.maximumWidth(), self.maximumHeight())
-
- def relayout(self, statusbar_size):
- self.statusbar_height = statusbar_size.height()
- self.do_layout()
-
- # }}}
-
- class BookDataDisplay(QLabel):
-
- mr = pyqtSignal(object)
- link_clicked = pyqtSignal(object)
-
- def __init__(self):
- QLabel.__init__(self)
- self.setText('')
- self.setWordWrap(True)
- self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
- self.linkActivated.connect(self.link_activated)
- self._link_clicked = False
-
- def mouseReleaseEvent(self, ev):
- QLabel.mouseReleaseEvent(self, ev)
- if not self._link_clicked:
- self.mr.emit(ev)
- self._link_clicked = False
-
- def link_activated(self, link):
- self._link_clicked = True
- link = unicode(link)
- self.link_clicked.emit(link)
-
- show_book_info = pyqtSignal()
-
- def __init__(self, clear_message):
- QWidget.__init__(self)
- self.setCursor(Qt.PointingHandCursor)
- self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
- self._layout = QHBoxLayout()
- self.setLayout(self._layout)
- self.clear_message = clear_message
- self.cover_display = BookInfoDisplay.BookCoverDisplay()
- self._layout.addWidget(self.cover_display)
- self.book_data = BookInfoDisplay.BookDataDisplay()
- self.book_data.mr.connect(self.mouseReleaseEvent)
- self._layout.addWidget(self.book_data)
- self.data = {}
- self.setVisible(False)
- self._layout.setAlignment(self.cover_display, Qt.AlignTop|Qt.AlignLeft)
-
- def mouseReleaseEvent(self, ev):
- ev.accept()
- self.show_book_info.emit()
-
- def show_data(self, data):
- if data.has_key('cover'):
- self.cover_display.setPixmap(QPixmap.fromImage(data.pop('cover')))
- else:
- self.cover_display.setPixmap(self.cover_display.default_pixmap)
-
- rows, comments = [], ''
- self.book_data.setText('')
- self.data = data.copy()
- rows = render_rows(self.data)
- rows = '\n'.join([u'%s: %s '%(k,t) for
- k, t in rows])
- if _('Comments') in self.data:
- comments = comments_to_html(self.data[_('Comments')])
- comments = ('%s: '%_('Comments'))+comments
- left_pane = u''%rows
- right_pane = u'%s
'%comments
- self.book_data.setText(u''
- % (left_pane, right_pane))
-
- self.clear_message()
- self.book_data.updateGeometry()
- self.updateGeometry()
- self.setVisible(True)
- self.setToolTip(''+_('Click to open Book Details window') +
- ' ' + _('Path') + ': ' + data.get(_('Path'), ''))
-
-
-
-class StatusBarInterface(object):
-
- def initialize(self, systray=None):
- self.systray = systray
- self.notifier = get_notifier(systray)
-
- def show_message(self, msg, timeout=0):
- QStatusBar.showMessage(self, msg, timeout)
- if self.notifier is not None and not config['disable_tray_notification']:
- if isosx and isinstance(msg, unicode):
- try:
- msg = msg.encode(preferred_encoding)
- except UnicodeEncodeError:
- msg = msg.encode('utf-8')
- self.notifier(msg)
-
- def clear_message(self):
- QStatusBar.clearMessage(self)
-
-class BookDetailsInterface(object):
-
- # These signals must be defined in the class implementing this interface
- files_dropped = None
- show_book_info = None
- open_containing_folder = None
- view_specific_format = None
-
- def reset_info(self):
- raise NotImplementedError()
-
- def show_data(self, data):
- raise NotImplementedError()
-
-class HStatusBar(QStatusBar, StatusBarInterface):
- pass
-
-class StatusBar(QStatusBar, StatusBarInterface, BookDetailsInterface):
-
- files_dropped = pyqtSignal(object, object)
- show_book_info = pyqtSignal()
- open_containing_folder = pyqtSignal(int)
- view_specific_format = pyqtSignal(int, object)
-
- resized = pyqtSignal(object)
-
- def initialize(self, systray=None):
- StatusBarInterface.initialize(self, systray=systray)
- self.book_info = BookInfoDisplay(self.clear_message)
- self.book_info.setAcceptDrops(True)
- self.scroll_area = QScrollArea()
- self.scroll_area.setWidget(self.book_info)
- self.scroll_area.setWidgetResizable(True)
- self.book_info.show_book_info.connect(self.show_book_info.emit,
- type=Qt.QueuedConnection)
- self.book_info.files_dropped.connect(self.files_dropped.emit,
- type=Qt.QueuedConnection)
- self.book_info.book_data.link_clicked.connect(self._link_clicked)
- self.addWidget(self.scroll_area, 100)
- self.setMinimumHeight(120)
- self.resized.connect(self.book_info.cover_display.relayout)
- self.book_info.cover_display.relayout(self.size())
-
-
- def _link_clicked(self, link):
- typ, _, val = link.partition(':')
- if typ == 'path':
- self.open_containing_folder.emit(int(val))
- elif typ == 'format':
- id_, fmt = val.split(':')
- self.view_specific_format.emit(int(id_), fmt)
- elif typ == 'devpath':
- QDesktopServices.openUrl(QUrl.fromLocalFile(val))
-
-
- def resizeEvent(self, ev):
- self.resized.emit(self.size())
-
- def reset_info(self):
- self.book_info.show_data({})
-
- def show_data(self, data):
- self.book_info.show_data(data)
-
diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py
index 2226520cf2..aa2d94a637 100644
--- a/src/calibre/gui2/ui.py
+++ b/src/calibre/gui2/ui.py
@@ -126,8 +126,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{
# Jobs Button {{{
self.job_manager = JobManager()
self.jobs_dialog = JobsDialog(self, self.job_manager)
- self.jobs_button = JobsButton(horizontal=config['gui_layout'] !=
- 'narrow')
+ self.jobs_button = JobsButton(horizontal=True)
self.jobs_button.initialize(self.jobs_dialog, self.job_manager)
# }}}
@@ -216,12 +215,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{
self.vanity.setText(self.vanity_template%dict(version=' ', device=' '))
self.device_info = ' '
UpdateMixin.__init__(self, opts)
- ####################### Status Bar #####################
- self.status_bar.initialize(self.system_tray_icon)
- self.book_details.show_book_info.connect(self.show_book_info)
- self.book_details.files_dropped.connect(self.files_dropped_on_book)
- self.book_details.open_containing_folder.connect(self.view_folder_for_id)
- self.book_details.view_specific_format.connect(self.view_format_by_id)
####################### Setup Toolbar #####################
ToolbarMixin.__init__(self)