mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
calibre now has a system tray icon
This commit is contained in:
parent
bd1d6ca3f3
commit
e9f3b6b735
@ -5,7 +5,8 @@ from xml.parsers.expat import ExpatError
|
||||
from functools import partial
|
||||
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, QUrl, QTimer
|
||||
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox, \
|
||||
QToolButton, QDialog, QDesktopServices, QFileDialog
|
||||
QToolButton, QDialog, QDesktopServices, QFileDialog, \
|
||||
QSystemTrayIcon, QApplication
|
||||
from PyQt4.QtSvg import QSvgRenderer
|
||||
|
||||
from calibre import __version__, __appname__, islinux, sanitize_file_name, \
|
||||
@ -20,12 +21,12 @@ from calibre.gui2 import APP_UID, warning_dialog, choose_files, error_dialog, \
|
||||
pixmap_to_data, choose_dir, ORG_NAME, \
|
||||
set_sidebar_directories, Dispatcher, \
|
||||
SingleApplication, Application, available_height, \
|
||||
max_available_height, config
|
||||
max_available_height, config, info_dialog
|
||||
from calibre.gui2.cover_flow import CoverFlow, DatabaseImages, pictureflowerror
|
||||
from calibre.library.database import LibraryDatabase
|
||||
from calibre.gui2.dialogs.scheduler import Scheduler
|
||||
from calibre.gui2.update import CheckForUpdates
|
||||
from calibre.gui2.main_window import MainWindow, option_parser
|
||||
from calibre.gui2.main_window import MainWindow, option_parser as _option_parser
|
||||
from calibre.gui2.main_ui import Ui_MainWindow
|
||||
from calibre.gui2.device import DeviceManager
|
||||
from calibre.gui2.status import StatusBar
|
||||
@ -91,7 +92,24 @@ class Main(MainWindow, Ui_MainWindow):
|
||||
self.device_connected = False
|
||||
self.viewers = collections.deque()
|
||||
self.content_server = None
|
||||
self.system_tray_icon = QSystemTrayIcon(QIcon(':/library'), self)
|
||||
if opts.no_systray:
|
||||
self.system_tray_icon.hide()
|
||||
else:
|
||||
self.system_tray_icon.show()
|
||||
self.system_tray_menu = QMenu()
|
||||
self.restore_action = self.system_tray_menu.addAction(QIcon(':/images/page.svg'), _('&Restore'))
|
||||
self.donate_action = self.system_tray_menu.addAction(QIcon(':/images/donate.svg'), _('&Donate'))
|
||||
self.quit_action = self.system_tray_menu.addAction(QIcon(':/images/window-close.svg'), _('&Quit'))
|
||||
|
||||
self.system_tray_icon.setContextMenu(self.system_tray_menu)
|
||||
self.connect(self.quit_action, SIGNAL('triggered(bool)'), self.quit)
|
||||
self.connect(self.donate_action, SIGNAL('triggered(bool)'), self.donate)
|
||||
self.connect(self.restore_action, SIGNAL('triggered(bool)'), lambda c : self.show())
|
||||
def sta(r):
|
||||
if r == QSystemTrayIcon.Trigger:
|
||||
self.hide() if self.isVisible() else self.show()
|
||||
self.connect(self.system_tray_icon, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), sta)
|
||||
####################### Location View ########################
|
||||
QObject.connect(self.location_view, SIGNAL('location_selected(PyQt_PyObject)'),
|
||||
self.location_selected)
|
||||
@ -109,7 +127,7 @@ class Main(MainWindow, Ui_MainWindow):
|
||||
self.update_found)
|
||||
self.update_checker.start()
|
||||
####################### Status Bar #####################
|
||||
self.status_bar = StatusBar(self.jobs_dialog)
|
||||
self.status_bar = StatusBar(self.jobs_dialog, self.system_tray_icon)
|
||||
self.setStatusBar(self.status_bar)
|
||||
QObject.connect(self.job_manager, SIGNAL('job_added(int)'), self.status_bar.job_added,
|
||||
Qt.QueuedConnection)
|
||||
@ -1238,21 +1256,52 @@ in which you want to store your books files. Any existing books will be automati
|
||||
self.library_view.write_settings()
|
||||
if self.device_connected:
|
||||
self.memory_view.write_settings()
|
||||
|
||||
def closeEvent(self, e):
|
||||
msg = 'There are active jobs. Are you sure you want to quit?'
|
||||
|
||||
def quit(self, checked):
|
||||
if self.shutdown():
|
||||
QApplication.instance().quit()
|
||||
|
||||
def donate(self):
|
||||
BUTTON = '''
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="1335186">
|
||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="">
|
||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
'''
|
||||
MSG = _('is the result of the efforts of many volunteers from all over the world. If you find it useful, please consider donating to support its development.')
|
||||
HTML = '''
|
||||
<html>
|
||||
<head>
|
||||
<title>Donate to support calibre</title>
|
||||
</head>
|
||||
<body style="background:white">
|
||||
<div><a href="http://calibre.kovidgoyal.net"><img style="border:0px" src="http://calibre.kovidgoyal.net/chrome/site/calibre_banner.png" alt="calibre" /></a></div>
|
||||
<p>Calibre %s</p>
|
||||
%s
|
||||
</body>
|
||||
</html>
|
||||
'''%(MSG, BUTTON)
|
||||
pt = PersistentTemporaryFile('_donate.htm')
|
||||
pt.write(HTML)
|
||||
pt.close()
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(pt.name))
|
||||
|
||||
|
||||
def shutdown(self):
|
||||
msg = _('There are active jobs. Are you sure you want to quit?')
|
||||
if self.job_manager.has_device_jobs():
|
||||
msg = '<p>'+__appname__ + ' is communicating with the device!<br>'+\
|
||||
'Quitting may cause corruption on the device.<br>'+\
|
||||
'Are you sure you want to quit?'
|
||||
msg = '<p>'+__appname__ + _(''' is communicating with the device!<br>
|
||||
'Quitting may cause corruption on the device.<br>
|
||||
'Are you sure you want to quit?''')+'</p>'
|
||||
if self.job_manager.has_jobs():
|
||||
d = QMessageBox(QMessageBox.Warning, 'WARNING: Active jobs', msg,
|
||||
d = QMessageBox(QMessageBox.Warning, _('WARNING: Active jobs'), msg,
|
||||
QMessageBox.Yes|QMessageBox.No, self)
|
||||
d.setIconPixmap(QPixmap(':/images/dialog_warning.svg'))
|
||||
d.setDefaultButton(QMessageBox.No)
|
||||
if d.exec_() != QMessageBox.Yes:
|
||||
e.ignore()
|
||||
return
|
||||
return False
|
||||
|
||||
self.job_manager.terminate_all_jobs()
|
||||
self.write_settings()
|
||||
@ -1269,7 +1318,22 @@ in which you want to store your books files. Any existing books will be automati
|
||||
time.sleep(2)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
e.accept()
|
||||
self.hide()
|
||||
return True
|
||||
|
||||
|
||||
def closeEvent(self, e):
|
||||
if self.system_tray_icon.isVisible():
|
||||
if not dynamic['systray_msg'] and not isosx:
|
||||
info_dialog(self, 'calibre', 'calibre '+_('will keep running in the system tray. To close it, choose <b>Quit</b> in the context menu of the system tray.')).exec_()
|
||||
dynamic['systray_msg'] = True
|
||||
self.hide()
|
||||
e.ignore()
|
||||
else:
|
||||
if self.shutdown():
|
||||
e.accept()
|
||||
else:
|
||||
e.ignore()
|
||||
|
||||
def update_found(self, version):
|
||||
os = 'windows' if iswindows else 'osx' if isosx else 'linux'
|
||||
@ -1286,21 +1350,27 @@ in which you want to store your books files. Any existing books will be automati
|
||||
dynamic.set('update to version %s'%version, False)
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
from calibre.utils.lock import singleinstance
|
||||
|
||||
pid = os.fork() if False and islinux else -1
|
||||
if pid <= 0:
|
||||
parser = option_parser('''\
|
||||
def option_parser():
|
||||
parser = _option_parser('''\
|
||||
%prog [opts] [path_to_ebook]
|
||||
|
||||
Launch the main calibre Graphical User Interface and optionally add the ebook at
|
||||
path_to_ebook to the database.
|
||||
''')
|
||||
parser.add_option('--with-library', default=None, action='store',
|
||||
help=_('Use the library located at the specified path.'))
|
||||
parser.add_option('-v', '--verbose', default=0, action='count',
|
||||
help=_('Log debugging information to console'))
|
||||
parser.add_option('--with-library', default=None, action='store',
|
||||
help=_('Use the library located at the specified path.'))
|
||||
parser.add_option('-v', '--verbose', default=0, action='count',
|
||||
help=_('Log debugging information to console'))
|
||||
parser.add_option('--no-systray', default=False, action='store_true',
|
||||
help=_('Disable system tray icon'))
|
||||
return parser
|
||||
|
||||
def main(args=sys.argv):
|
||||
from calibre.utils.lock import singleinstance
|
||||
|
||||
pid = os.fork() if False and islinux else -1
|
||||
if pid <= 0:
|
||||
parser = option_parser()
|
||||
opts, args = parser.parse_args(args)
|
||||
if opts.with_library is not None and os.path.isdir(opts.with_library):
|
||||
prefs.set('library_path', opts.with_library)
|
||||
|
@ -164,8 +164,9 @@ class TagViewButton(QToolButton):
|
||||
|
||||
|
||||
class StatusBar(QStatusBar):
|
||||
def __init__(self, jobs_dialog):
|
||||
def __init__(self, jobs_dialog, systray=None):
|
||||
QStatusBar.__init__(self)
|
||||
self.systray = systray
|
||||
self.movie_button = MovieButton(QMovie(':/images/jobs-animated.mng'), jobs_dialog)
|
||||
self.cover_flow_button = CoverFlowButton()
|
||||
self.tag_view_button = TagViewButton()
|
||||
@ -179,6 +180,11 @@ class StatusBar(QStatusBar):
|
||||
|
||||
def reset_info(self):
|
||||
self.book_info.show_data({})
|
||||
|
||||
def showMessage(self, msg, timeout=0):
|
||||
if self.systray is not None:
|
||||
self.systray.showMessage('calibre', msg, self.systray.Information, 10000)
|
||||
return QStatusBar.showMessage(self, msg, timeout)
|
||||
|
||||
def jobs(self):
|
||||
src = qstring_to_unicode(self.movie_button.jobs.text())
|
||||
|
@ -183,7 +183,8 @@ def setup_completion(fatal_errors):
|
||||
from calibre.ebooks.odt.to_oeb import option_parser as odt2oeb
|
||||
from calibre.ebooks.epub.from_feeds import option_parser as feeds2epub
|
||||
from calibre.ebooks.epub.from_any import option_parser as any2epub
|
||||
from calibre.ebooks.epub.from_comic import option_parser as comic2epub
|
||||
from calibre.ebooks.epub.from_comic import option_parser as comic2epub
|
||||
from calibre.gui2.main import option_parser as guiop
|
||||
any_formats = ['epub', 'htm', 'html', 'xhtml', 'xhtm', 'rar', 'zip',
|
||||
'txt', 'lit', 'rtf', 'pdf', 'prc', 'mobi', 'fb2', 'odt']
|
||||
f = open_file('/etc/bash_completion.d/libprs500')
|
||||
@ -204,6 +205,7 @@ def setup_completion(fatal_errors):
|
||||
f.write(opts_and_exts('fb22lrf', htmlop, ['fb2']))
|
||||
f.write(opts_and_exts('pdf2lrf', htmlop, ['pdf']))
|
||||
f.write(opts_and_exts('any2lrf', htmlop, any_formats))
|
||||
f.write(opts_and_exts('calibre', guiop, any_formats))
|
||||
f.write(opts_and_exts('any2lrf', any2epub, any_formats))
|
||||
f.write(opts_and_exts('lrf2lrs', lrf2lrsop, ['lrf']))
|
||||
f.write(opts_and_exts('lrf-meta', metaop, ['lrf']))
|
||||
|
Loading…
x
Reference in New Issue
Block a user