From 7b34aa9e77310c8386de28410409707b60c80e54 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 08:47:01 -0600 Subject: [PATCH 01/11] Display rating in cover browser --- src/calibre/gui2/cover_flow.py | 7 ++++++ src/calibre/gui2/library/models.py | 5 +++++ src/calibre/gui2/pictureflow/pictureflow.cpp | 23 +++++++++++++++----- src/calibre/gui2/pictureflow/pictureflow.h | 1 + src/calibre/gui2/pictureflow/pictureflow.sip | 1 + 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/calibre/gui2/cover_flow.py b/src/calibre/gui2/cover_flow.py index 5dca2c8e72..c72f53201f 100644 --- a/src/calibre/gui2/cover_flow.py +++ b/src/calibre/gui2/cover_flow.py @@ -67,6 +67,13 @@ if pictureflow is not None: ans = '' return ans + def subtitle(self, index): + try: + return u'\u2605'*self.model.rating(index) + except: + pass + return '' + def reset(self): self.dataChanged.emit() diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 7ffbc42f02..3bbab52b33 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -492,6 +492,11 @@ class BooksModel(QAbstractTableModel): # {{{ def title(self, row_number): return self.db.title(row_number) + def rating(self, row_number): + ans = self.db.rating(row_number) + ans = ans/2 if ans else 0 + return int(ans) + def cover(self, row_number): data = None try: diff --git a/src/calibre/gui2/pictureflow/pictureflow.cpp b/src/calibre/gui2/pictureflow/pictureflow.cpp index 450608cf6b..1c63ec410c 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.cpp +++ b/src/calibre/gui2/pictureflow/pictureflow.cpp @@ -706,9 +706,12 @@ void PictureFlowPrivate::render() painter.setPen(Qt::white); //painter.setPen(QColor(255,255,255,127)); - if (centerIndex < slideCount() && centerIndex > -1) - painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2-fontSize*3), + if (centerIndex < slideCount() && centerIndex > -1) { + painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2-fontSize*4), Qt::AlignCenter, slideImages->caption(centerIndex)); + painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2-fontSize*2), + Qt::AlignCenter, slideImages->subtitle(centerIndex)); + } painter.end(); @@ -759,15 +762,22 @@ void PictureFlowPrivate::render() int sc = slideCount(); painter.setPen(QColor(255,255,255, (255-fade) )); - if (leftTextIndex < sc && leftTextIndex > -1) - painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2 - fontSize*3), + if (leftTextIndex < sc && leftTextIndex > -1) { + painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2 - fontSize*4), Qt::AlignCenter, slideImages->caption(leftTextIndex)); + painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2 - fontSize*2), + Qt::AlignCenter, slideImages->subtitle(leftTextIndex)); + + } painter.setPen(QColor(255,255,255, fade)); - if (leftTextIndex+1 < sc && leftTextIndex > -2) - painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2 - fontSize*3), + if (leftTextIndex+1 < sc && leftTextIndex > -2) { + painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2 - fontSize*4), Qt::AlignCenter, slideImages->caption(leftTextIndex+1)); + painter.drawText( QRect(0,0, buffer.width(), buffer.height()*2 - fontSize*2), + Qt::AlignCenter, slideImages->subtitle(leftTextIndex+1)); + } painter.end(); } @@ -1372,5 +1382,6 @@ void PictureFlow::emitcurrentChanged(int index) { emit currentChanged(index); } int FlowImages::count() { return 0; } QImage FlowImages::image(int index) { index=0; return QImage(); } QString FlowImages::caption(int index) {index=0; return QString(); } +QString FlowImages::subtitle(int index) {index=0; return QString(); } // }}} diff --git a/src/calibre/gui2/pictureflow/pictureflow.h b/src/calibre/gui2/pictureflow/pictureflow.h index 13477a8771..f2c2c947e6 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.h +++ b/src/calibre/gui2/pictureflow/pictureflow.h @@ -67,6 +67,7 @@ public: virtual int count(); virtual QImage image(int index); virtual QString caption(int index); + virtual QString subtitle(int index); signals: void dataChanged(); diff --git a/src/calibre/gui2/pictureflow/pictureflow.sip b/src/calibre/gui2/pictureflow/pictureflow.sip index f7ba12cee7..f05f0ee3d1 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.sip +++ b/src/calibre/gui2/pictureflow/pictureflow.sip @@ -16,6 +16,7 @@ public: virtual int count(); virtual QImage image(int index); virtual QString caption(int index); + virtual QString subtitle(int index); signals: void dataChanged(); From b8f400aad35b94afc17b0aefec1e5f41c3d32a7a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 09:05:33 -0600 Subject: [PATCH 02/11] ... --- resources/recipes/singtao_daily.recipe | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/recipes/singtao_daily.recipe b/resources/recipes/singtao_daily.recipe index bb5280c062..4146231d7d 100644 --- a/resources/recipes/singtao_daily.recipe +++ b/resources/recipes/singtao_daily.recipe @@ -32,11 +32,11 @@ class AdvancedUserRecipe1278063072(BasicNewsRecipe): feeds = [] for title, url in [ ('Editorial', 'http://news.singtao.ca/toronto/editorial.html'), - ('Toronto \xe5\x9f\x8e\xe5\xb8\x82/\xe7\xa4\xbe\xe5\x8d\x80', 'http://news.singtao.ca/toronto/city.html'), - ('Canada \xe5\x8a\xa0\xe5\x9c\x8b', 'http://news.singtao.ca/toronto/canada.html'), + (u'Toronto \xe5\x9f\x8e\xe5\xb8\x82/\xe7\xa4\xbe\xe5\x8d\x80', 'http://news.singtao.ca/toronto/city.html'), + (u'Canada \xe5\x8a\xa0\xe5\x9c\x8b', 'http://news.singtao.ca/toronto/canada.html'), ('Entertainment', 'http://news.singtao.ca/toronto/entertainment.html'), ('World', 'http://news.singtao.ca/toronto/world.html'), - ('Finance \xe5\x9c\x8b\xe9\x9a\x9b\xe8\xb2\xa1\xe7\xb6\x93', 'http://news.singtao.ca/toronto/finance.html'), + (u'Finance \xe5\x9c\x8b\xe9\x9a\x9b\xe8\xb2\xa1\xe7\xb6\x93', 'http://news.singtao.ca/toronto/finance.html'), ('Sports', 'http://news.singtao.ca/toronto/sports.html'), ]: articles = self.parse_section(url) From 5f93eb14a1998e8ebffd87b85c55cea9d79a0c7a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 09:09:51 -0600 Subject: [PATCH 03/11] ... --- resources/recipes/singtao_daily.recipe | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/resources/recipes/singtao_daily.recipe b/resources/recipes/singtao_daily.recipe index 4146231d7d..f25014ed9a 100644 --- a/resources/recipes/singtao_daily.recipe +++ b/resources/recipes/singtao_daily.recipe @@ -31,13 +31,19 @@ class AdvancedUserRecipe1278063072(BasicNewsRecipe): def parse_index(self): feeds = [] for title, url in [ - ('Editorial', 'http://news.singtao.ca/toronto/editorial.html'), - (u'Toronto \xe5\x9f\x8e\xe5\xb8\x82/\xe7\xa4\xbe\xe5\x8d\x80', 'http://news.singtao.ca/toronto/city.html'), - (u'Canada \xe5\x8a\xa0\xe5\x9c\x8b', 'http://news.singtao.ca/toronto/canada.html'), - ('Entertainment', 'http://news.singtao.ca/toronto/entertainment.html'), - ('World', 'http://news.singtao.ca/toronto/world.html'), - (u'Finance \xe5\x9c\x8b\xe9\x9a\x9b\xe8\xb2\xa1\xe7\xb6\x93', 'http://news.singtao.ca/toronto/finance.html'), - ('Sports', 'http://news.singtao.ca/toronto/sports.html'), + ('Editorial', + 'http://news.singtao.ca/toronto/editorial.html'), + ('Toronto \xe5\x9f\x8e\xe5\xb8\x82/\xe7\xa4\xbe\xe5\x8d\x80'.decode('utf-8'), + 'http://news.singtao.ca/toronto/city.html'), + ('Canada \xe5\x8a\xa0\xe5\x9c\x8b'.decode('utf-8'), + 'http://news.singtao.ca/toronto/canada.html'), + ('Entertainment', + 'http://news.singtao.ca/toronto/entertainment.html'), + ('World', + 'http://news.singtao.ca/toronto/world.html'), + ('Finance \xe5\x9c\x8b\xe9\x9a\x9b\xe8\xb2\xa1\xe7\xb6\x93'.decode('utf-8'), + 'http://news.singtao.ca/toronto/finance.html'), + ('Sports', 'http://news.singtao.ca/toronto/sports.html'), ]: articles = self.parse_section(url) if articles: From d33a9dc0b58a899e1a24f545c87b6249b8de1bff Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 11:36:38 -0600 Subject: [PATCH 04/11] Add status tips for all active elements in the main GUI --- src/calibre/gui2/init.py | 7 ++++--- src/calibre/gui2/main.ui | 2 +- src/calibre/gui2/search_box.py | 12 ++++++++++++ src/calibre/gui2/search_restriction_mixin.py | 1 + src/calibre/gui2/tag_view.py | 10 ++++++++++ src/calibre/gui2/ui.py | 1 + src/calibre/gui2/widgets.py | 18 ++++++++++++------ 7 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index f918a5843c..8ac36e06b9 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -20,7 +20,6 @@ from calibre.gui2.tag_view import TagBrowserWidget from calibre.gui2.book_details import BookDetails from calibre.gui2.notify import get_notifier - _keep_refs = [] def partial(*args, **kwargs): @@ -182,6 +181,7 @@ class ToolbarMixin(object): # {{{ for ch in self.tool_bar.children(): if isinstance(ch, QToolButton): ch.setCursor(Qt.PointingHandCursor) + ch.setStatusTip(ch.toolTip()) self.tool_bar.contextMenuEvent = self.no_op @@ -367,7 +367,7 @@ class StatusBar(QStatusBar): # {{{ self.notifier = get_notifier(systray) def show_message(self, msg, timeout=0): - QStatusBar.showMessage(self, msg, timeout) + self.showMessage(msg, timeout) if self.notifier is not None and not config['disable_tray_notification']: if isosx and isinstance(msg, unicode): try: @@ -377,7 +377,8 @@ class StatusBar(QStatusBar): # {{{ self.notifier(msg) def clear_message(self): - QStatusBar.clearMessage(self) + self.clearMessage() + # }}} diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui index c863ff28f5..a05796a6cb 100644 --- a/src/calibre/gui2/main.ui +++ b/src/calibre/gui2/main.ui @@ -259,7 +259,7 @@ - Choose saved search or enter name for new saved search + 15 diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index ef0c6b1455..dd7d0a63a0 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -6,6 +6,8 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' +import re + from PyQt4.Qt import QComboBox, Qt, QLineEdit, QStringList, pyqtSlot, \ pyqtSignal, SIGNAL, QObject, QDialog, QCompleter, \ QAction, QKeySequence @@ -368,6 +370,10 @@ class SearchBoxMixin(object): self.action_focus_search.triggered.connect(lambda x: self.search.setFocus(Qt.OtherFocusReason)) self.addAction(self.action_focus_search) + self.search.setStatusTip(re.sub(r'<\w+>', ' ', + unicode(self.search.toolTip()))) + self.advanced_search_button.setStatusTip(self.advanced_search_button.toolTip()) + self.clear_button.setStatusTip(self.clear_button.toolTip()) def search_box_cleared(self): self.tags_view.clear() @@ -396,6 +402,12 @@ class SavedSearchBoxMixin(object): self.saved_search.delete_search_button_clicked) self.connect(self.copy_search_button, SIGNAL('clicked()'), self.saved_search.copy_search_button_clicked) + self.saved_search.setToolTip( + _('Choose saved search or enter name for new saved search')) + self.saved_search.setStatusTip(self.saved_search.toolTip()) + for x in ('copy', 'save', 'delete'): + b = getattr(self, x+'_search_button') + b.setStatusTip(b.toolTip()) def saved_searches_changed(self): diff --git a/src/calibre/gui2/search_restriction_mixin.py b/src/calibre/gui2/search_restriction_mixin.py index 287c3b2fc2..3a71fa3de0 100644 --- a/src/calibre/gui2/search_restriction_mixin.py +++ b/src/calibre/gui2/search_restriction_mixin.py @@ -11,6 +11,7 @@ class SearchRestrictionMixin(object): self.library_view.model().count_changed_signal.connect(self.restriction_count_changed) self.search_restriction.setSizeAdjustPolicy(self.search_restriction.AdjustToMinimumContentsLengthWithIcon) self.search_restriction.setMinimumContentsLength(10) + self.search_restriction.setStatusTip(self.search_restriction.toolTip()) ''' Adding and deleting books while restricted creates a complexity. When added, diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 189caea6ea..2a9fb129ac 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -768,6 +768,9 @@ class TagBrowserWidget(QWidget): # {{{ for x in (_('Sort by name'), _('Sort by popularity'), _('Sort by average rating')): parent.sort_by.addItem(x) + parent.sort_by.setToolTip( + _('Set the sort order for entries in the Tag Browser')) + parent.sort_by.setStatusTip(parent.sort_by.toolTip()) parent.sort_by.setCurrentIndex(0) self._layout.addWidget(parent.sort_by) @@ -776,9 +779,16 @@ class TagBrowserWidget(QWidget): # {{{ parent.tag_match.addItem(x) parent.tag_match.setCurrentIndex(0) self._layout.addWidget(parent.tag_match) + parent.tag_match.setToolTip( + _('When selecting multiple entries in the Tag Browser ' + 'match any or all of them')) + parent.tag_match.setStatusTip(parent.tag_match.toolTip()) parent.edit_categories = QPushButton(_('Manage &user categories'), parent) self._layout.addWidget(parent.edit_categories) + parent.edit_categories.setToolTip( + _('Add your own categories to the Tag Browser')) + parent.edit_categories.setStatusTip(parent.edit_categories.toolTip()) # }}} diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 756e375e23..9a3ab86750 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -163,6 +163,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{ self.donate_action = self.system_tray_menu.addAction( QIcon(I('donate.svg')), _('&Donate to support calibre')) self.donate_button.setDefaultAction(self.donate_action) + self.donate_button.setStatusTip(self.donate_button.toolTip()) self.eject_action = self.system_tray_menu.addAction( QIcon(I('eject.svg')), _('&Eject connected device')) self.eject_action.setEnabled(False) diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index d46c020484..d94d8e7292 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -298,6 +298,14 @@ class LocationModel(QAbstractListModel): row = 3 return row + def get_tooltip(self, row, drow): + ans = self.tooltips[row] + if row > 0: + fs = self.free[drow-1] + if fs > -1: + ans += '\n\n%s '%(human_readable(fs)) + _('free') + return ans + def data(self, index, role): row = index.row() drow = self.get_device_row(row) @@ -308,12 +316,8 @@ class LocationModel(QAbstractListModel): data = QVariant(text) elif role == Qt.DecorationRole: data = self.icons[drow] - elif role == Qt.ToolTipRole: - ans = self.tooltips[row] - if row > 0: - fs = self.free[drow-1] - if fs > -1: - ans += '\n\n%s '%(human_readable(fs)) + _('free') + elif role in (Qt.ToolTipRole, Qt.StatusTipRole): + ans = self.get_tooltip(row, drow) data = QVariant(ans) elif role == Qt.SizeHintRole: data = QVariant(QSize(155, 90)) @@ -1011,12 +1015,14 @@ class LayoutButton(QToolButton): label =_('Show') self.setText(label + ' ' + self.label) self.setToolTip(self.text()) + self.setStatusTip(self.text()) def set_state_to_hide(self, *args): self.setChecked(True) label = _('Hide') self.setText(label + ' ' + self.label) self.setToolTip(self.text()) + self.setStatusTip(self.text()) def update_state(self, *args): if self.splitter.is_side_index_hidden: From 9370e50d593ca7c733eeb340c9a8989c3c497025 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 12:05:13 -0600 Subject: [PATCH 05/11] Add help button to main toolbar --- resources/images/help.svg | 269 ++++++++++++++++++++++++++++++++++++++ src/calibre/gui2/init.py | 16 ++- src/calibre/gui2/main.ui | 17 +++ 3 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 resources/images/help.svg diff --git a/resources/images/help.svg b/resources/images/help.svg new file mode 100644 index 0000000000..be41385b7d --- /dev/null +++ b/resources/images/help.svg @@ -0,0 +1,269 @@ + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 8ac36e06b9..056d0c0d1d 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -8,12 +8,12 @@ __docformat__ = 'restructuredtext en' import functools from PyQt4.Qt import QMenu, Qt, pyqtSignal, QToolButton, QIcon, QStackedWidget, \ - QSize, QSizePolicy, QStatusBar + QSize, QSizePolicy, QStatusBar, QUrl from calibre.utils.config import prefs from calibre.ebooks import BOOK_EXTENSIONS from calibre.constants import isosx, __appname__, preferred_encoding -from calibre.gui2 import config, is_widescreen +from calibre.gui2 import config, is_widescreen, open_url from calibre.gui2.library.views import BooksView, DeviceBooksView from calibre.gui2.widgets import Splitter from calibre.gui2.tag_view import TagBrowserWidget @@ -47,6 +47,7 @@ class SaveMenu(QMenu): # {{{ class ToolbarMixin(object): # {{{ def __init__(self): + self.action_help.triggered.connect(self.show_help) md = QMenu() md.addAction(_('Edit metadata individually'), partial(self.edit_metadata, False, bulk=False)) @@ -185,6 +186,9 @@ class ToolbarMixin(object): # {{{ self.tool_bar.contextMenuEvent = self.no_op + def show_help(self, *args): + open_url(QUrl('http://calibre-ebook.com/user_manual')) + def read_toolbar_settings(self): self.tool_bar.setIconSize(config['toolbar_icon_size']) self.tool_bar.setToolButtonStyle( @@ -363,8 +367,12 @@ class Stack(QStackedWidget): # {{{ class StatusBar(QStatusBar): # {{{ def initialize(self, systray=None): + self.default_message = 'Welcome to calibre' self.systray = systray self.notifier = get_notifier(systray) + self.messageChanged.connect(self.message_changed, + type=Qt.QueuedConnection) + self.message_changed('') def show_message(self, msg, timeout=0): self.showMessage(msg, timeout) @@ -379,6 +387,10 @@ class StatusBar(QStatusBar): # {{{ def clear_message(self): self.clearMessage() + def message_changed(self, msg): + if not msg or msg.isEmpty() or msg.isNull(): + self.showMessage(self.default_message) + # }}} diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui index a05796a6cb..7720f308a3 100644 --- a/src/calibre/gui2/main.ui +++ b/src/calibre/gui2/main.ui @@ -353,6 +353,8 @@ + + @@ -544,6 +546,21 @@ Ctrl+P + + + + :/images/help.svg:/images/help.svg + + + Help + + + Browse the calibre User Manual + + + F1 + + From 7e4673f2937a5cd245b13a56e5e910f27a740010 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 13:06:07 -0600 Subject: [PATCH 06/11] Remove vanity and move its functionality to the status bar --- src/calibre/gui2/device.py | 9 ++------ src/calibre/gui2/init.py | 43 +++++++++++++++++++++++++++++++++----- src/calibre/gui2/main.ui | 28 +------------------------ src/calibre/gui2/ui.py | 15 ++----------- src/calibre/gui2/update.py | 8 ++----- 5 files changed, 45 insertions(+), 58 deletions(-) diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 4acde6089b..39a53002e2 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -758,10 +758,8 @@ class DeviceMixin(object): # {{{ self.refresh_ondevice_info (device_connected = True, reset_only = True) else: self.device_connected = None + self.status_bar.device_disconnected() self.location_view.model().update_devices() - self.vanity.setText(self.vanity_template%\ - dict(version=self.latest_version, device=' ')) - self.device_info = ' ' if self.current_view() != self.library_view: self.book_details.reset_info() self.location_view.setCurrentIndex(self.location_view.model().index(0)) @@ -775,10 +773,7 @@ class DeviceMixin(object): # {{{ return self.device_job_exception(job) info, cp, fs = job.result self.location_view.model().update_devices(cp, fs) - self.device_info = _('Connected ')+info[0] - self.vanity.setText(self.vanity_template%\ - dict(version=self.latest_version, device=self.device_info)) - + self.status_bar.device_connected(info[0]) self.device_manager.books(Dispatcher(self.metadata_downloaded)) def metadata_downloaded(self, job): diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 056d0c0d1d..d9a3835623 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -5,14 +5,15 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import functools +import functools, sys, os from PyQt4.Qt import QMenu, Qt, pyqtSignal, QToolButton, QIcon, QStackedWidget, \ - QSize, QSizePolicy, QStatusBar, QUrl + QSize, QSizePolicy, QStatusBar, QUrl, QLabel from calibre.utils.config import prefs from calibre.ebooks import BOOK_EXTENSIONS -from calibre.constants import isosx, __appname__, preferred_encoding +from calibre.constants import isosx, __appname__, preferred_encoding, \ + __version__ from calibre.gui2 import config, is_widescreen, open_url from calibre.gui2.library.views import BooksView, DeviceBooksView from calibre.gui2.widgets import Splitter @@ -366,14 +367,43 @@ class Stack(QStackedWidget): # {{{ class StatusBar(QStatusBar): # {{{ + def __init__(self, parent=None): + QStatusBar.__init__(self, parent) + self.default_message = __appname__ + ' ' + _('version') + ' ' + \ + self.get_version() + ' ' + _('created by Kovid Goyal') + self.device_string = '' + self.update_label = QLabel('') + self.update_label.setOpenExternalLinks(True) + self.addPermanentWidget(self.update_label) + def initialize(self, systray=None): - self.default_message = 'Welcome to calibre' self.systray = systray self.notifier = get_notifier(systray) self.messageChanged.connect(self.message_changed, type=Qt.QueuedConnection) self.message_changed('') + def device_connected(self, devname): + self.device_string = _('Connected ') + devname + self.clearMessage() + + def device_disconnected(self): + self.device_string = '' + self.clearMessage() + + def new_version_available(self, ver, url): + msg = (u'%s: %s') % ( + _('Update found'), url, ver) + self.update_label.setText(msg) + self.update_label.setCursor(Qt.PointingHandCursor) + + def get_version(self): + dv = os.environ.get('CALIBRE_DEVELOP_FROM', None) + v = __version__ + if getattr(sys, 'frozen', False) and dv and os.path.abspath(dv) in sys.path: + v += '*' + return v + def show_message(self, msg, timeout=0): self.showMessage(msg, timeout) if self.notifier is not None and not config['disable_tray_notification']: @@ -389,7 +419,10 @@ class StatusBar(QStatusBar): # {{{ def message_changed(self, msg): if not msg or msg.isEmpty() or msg.isNull(): - self.showMessage(self.default_message) + extra = '' + if self.device_string: + extra = ' ..::.. ' + self.device_string + self.showMessage(self.default_message + extra) # }}} diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui index 7720f308a3..da2722a0a5 100644 --- a/src/calibre/gui2/main.ui +++ b/src/calibre/gui2/main.ui @@ -119,33 +119,7 @@ - - - - - - 0 - 0 - - - - - 16777215 - 90 - - - - - - - Qt::RichText - - - true - - - - + diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 9a3ab86750..10cef9b2cb 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -19,7 +19,7 @@ from PyQt4.Qt import Qt, SIGNAL, QObject, QTimer, \ QMessageBox, QHelpEvent from calibre import prints, patheq -from calibre.constants import __version__, __appname__, isosx +from calibre.constants import __appname__, isosx from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.config import prefs, dynamic from calibre.utils.ipc.server import Server @@ -203,18 +203,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{ self.device_manager.umount_device) self.eject_action.triggered.connect(self.device_manager.umount_device) - ####################### Vanity ######################## - self.vanity_template = _('

For help see the: User Manual' - '
')%'http://calibre-ebook.com/user_manual' - dv = os.environ.get('CALIBRE_DEVELOP_FROM', None) - v = __version__ - if getattr(sys, 'frozen', False) and dv and os.path.abspath(dv) in sys.path: - v += '*' - self.vanity_template += _('%s: %s by Kovid Goyal ' - '%%(version)s
%%(device)s

')%(__appname__, v) - self.latest_version = ' ' - self.vanity.setText(self.vanity_template%dict(version=' ', device=' ')) - self.device_info = ' ' + #################### Update notification ################### UpdateMixin.__init__(self, opts) ####################### Setup Toolbar ##################### diff --git a/src/calibre/gui2/update.py b/src/calibre/gui2/update.py index 84168d17b5..38612c46f2 100644 --- a/src/calibre/gui2/update.py +++ b/src/calibre/gui2/update.py @@ -49,12 +49,8 @@ class UpdateMixin(object): def update_found(self, version): os = 'windows' if iswindows else 'osx' if isosx else 'linux' url = 'http://calibre-ebook.com/download_%s'%os - self.latest_version = '
' + _('' - 'Latest version: %s')%(url, version) - self.vanity.setText(self.vanity_template%\ - (dict(version=self.latest_version, - device=self.device_info))) - self.vanity.update() + self.status_bar.new_version_available(version, url) + if config.get('new_version_notification') and \ dynamic.get('update to version %s'%version, True): if question_dialog(self, _('Update available'), From e62b8afcf30d9f20038fc36f16c4f19313176b24 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 13:20:22 -0600 Subject: [PATCH 07/11] Get rid of the annoying link not detected messages --- resources/images/dialog_information.svg | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/resources/images/dialog_information.svg b/resources/images/dialog_information.svg index 995f74cd78..1c3d34add1 100644 --- a/resources/images/dialog_information.svg +++ b/resources/images/dialog_information.svg @@ -1752,7 +1752,7 @@ sodipodi:cy="93.331604" sodipodi:cx="-166.53223" id="path6082" - style="opacity:1;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter6074)" + style="opacity:1;fill:url(#radialGradient6084);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.08779998;stroke-opacity:1;filter:url(#filter6074)" sodipodi:type="arc" /> - - Date: Sun, 4 Jul 2010 13:24:47 -0600 Subject: [PATCH 08/11] Make statusbar text bold --- src/calibre/gui2/init.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index d9a3835623..5a98362d32 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import functools, sys, os from PyQt4.Qt import QMenu, Qt, pyqtSignal, QToolButton, QIcon, QStackedWidget, \ - QSize, QSizePolicy, QStatusBar, QUrl, QLabel + QSize, QSizePolicy, QStatusBar, QUrl, QLabel, QFont from calibre.utils.config import prefs from calibre.ebooks import BOOK_EXTENSIONS @@ -375,6 +375,9 @@ class StatusBar(QStatusBar): # {{{ self.update_label = QLabel('') self.update_label.setOpenExternalLinks(True) self.addPermanentWidget(self.update_label) + self._font = QFont() + self._font.setBold(True) + self.setFont(self._font) def initialize(self, systray=None): self.systray = systray From c14020f84d1087114c89a45d8759ba67bb09ce5f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 15:36:31 -0600 Subject: [PATCH 09/11] Make the heart throb --- src/calibre/gui2/main.ui | 16 ++++----- src/calibre/gui2/throbber.py | 70 ++++++++++++++++++++++++++++++++++++ src/calibre/gui2/ui.py | 2 ++ 3 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/calibre/gui2/throbber.py diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui index da2722a0a5..d89a451cda 100644 --- a/src/calibre/gui2/main.ui +++ b/src/calibre/gui2/main.ui @@ -96,10 +96,7 @@ - - - PointingHandCursor - + ... @@ -107,12 +104,6 @@ :/images/donate.svg:/images/donate.svg - - - 64 - 64 - - true @@ -552,6 +543,11 @@ QComboBox
calibre.gui2.search_box
+ + ThrobbingButton + QToolButton +
calibre/gui2/throbber.h
+
diff --git a/src/calibre/gui2/throbber.py b/src/calibre/gui2/throbber.py new file mode 100644 index 0000000000..99c899c9f3 --- /dev/null +++ b/src/calibre/gui2/throbber.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2010, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + +from PyQt4.Qt import QToolButton, QSize, QPropertyAnimation, Qt, \ + QMetaObject + +from calibre.gui2 import config + +class ThrobbingButton(QToolButton): + + def __init__(self, *args): + QToolButton.__init__(self, *args) + self.animation = QPropertyAnimation(self, 'iconSize', self) + self.animation.setDuration(60/72.*1000) + self.animation.setLoopCount(4) + self.normal_icon_size = QSize(64, 64) + self.animation.valueChanged.connect(self.value_changed) + self.setCursor(Qt.PointingHandCursor) + self.animation.finished.connect(self.animation_finished) + + def set_normal_icon_size(self, w, h): + self.normal_icon_size = QSize(w, h) + self.setIconSize(self.normal_icon_size) + self.setMinimumSize(self.sizeHint()) + + def animation_finished(self): + self.setIconSize(self.normal_icon_size) + + def enterEvent(self, ev): + self.start_animation() + + def leaveEvent(self, ev): + self.stop_animation() + + def value_changed(self, val): + self.update() + + def start_animation(self): + if config['disable_animations']: return + if self.animation.state() != self.animation.Stopped or not self.isVisible(): + return + size = self.normal_icon_size.width() + smaller = int(0.7 * size) + self.animation.setStartValue(QSize(smaller, smaller)) + self.animation.setEndValue(self.normal_icon_size) + QMetaObject.invokeMethod(self.animation, 'start', Qt.QueuedConnection) + + def stop_animation(self): + self.animation.stop() + self.animation_finished() + + +if __name__ == '__main__': + from PyQt4.Qt import QApplication, QWidget, QHBoxLayout, QIcon + app = QApplication([]) + w = QWidget() + w.setLayout(QHBoxLayout()) + b = ThrobbingButton() + b.setIcon(QIcon(I('donate.svg'))) + w.layout().addWidget(b) + w.show() + b.set_normal_icon_size(64, 64) + b.start_animation() + + app.exec_() diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 10cef9b2cb..709f91da25 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -281,6 +281,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{ self.read_settings() self.finalize_layout() + self.donate_button.set_normal_icon_size(64, 64) + self.donate_button.start_animation() def resizeEvent(self, ev): MainWindow.resizeEvent(self, ev) From 6680a1c3f074269cff56550330f9ad7f27f1416f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 15:41:39 -0600 Subject: [PATCH 10/11] ... --- src/calibre/gui2/init.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 5a98362d32..8aaeab3a8a 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -375,6 +375,7 @@ class StatusBar(QStatusBar): # {{{ self.update_label = QLabel('') self.update_label.setOpenExternalLinks(True) self.addPermanentWidget(self.update_label) + self.update_label.setVisible(False) self._font = QFont() self._font.setBold(True) self.setFont(self._font) @@ -399,6 +400,7 @@ class StatusBar(QStatusBar): # {{{ _('Update found'), url, ver) self.update_label.setText(msg) self.update_label.setCursor(Qt.PointingHandCursor) + self.update_label.setVisible(True) def get_version(self): dv = os.environ.get('CALIBRE_DEVELOP_FROM', None) From 2d18d57c5d22eedb7fc709f31a583a92a7172500 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 4 Jul 2010 16:37:46 -0600 Subject: [PATCH 11/11] Add option to hide donate button --- src/calibre/gui2/dialogs/config/__init__.py | 2 ++ src/calibre/gui2/dialogs/config/config.ui | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/dialogs/config/__init__.py b/src/calibre/gui2/dialogs/config/__init__.py index 144d8f8586..bf9dc0a623 100644 --- a/src/calibre/gui2/dialogs/config/__init__.py +++ b/src/calibre/gui2/dialogs/config/__init__.py @@ -495,6 +495,7 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): li = i self.opt_gui_layout.setCurrentIndex(li) self.opt_disable_animations.setChecked(config['disable_animations']) + self.opt_show_donate_button.setChecked(config['show_donate_button']) def check_port_value(self, *args): port = self.port.value() @@ -871,6 +872,7 @@ class ConfigDialog(ResizableDialog, Ui_Dialog): config['overwrite_author_title_metadata'] = self.opt_overwrite_author_title_metadata.isChecked() config['enforce_cpu_limit'] = bool(self.opt_enforce_cpu_limit.isChecked()) config['disable_animations'] = bool(self.opt_disable_animations.isChecked()) + config['show_donate_button'] = bool(self.opt_show_donate_button.isChecked()) gprefs['show_splash_screen'] = bool(self.show_splash_screen.isChecked()) fmts = [] for i in range(self.viewer.count()): diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui index 191b8def80..b473ee7846 100644 --- a/src/calibre/gui2/dialogs/config/config.ui +++ b/src/calibre/gui2/dialogs/config/config.ui @@ -356,7 +356,7 @@ - + Show &splash screen at startup @@ -665,6 +665,13 @@ + + + + Show &donate button (restart) + + +