mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implemented GUI for news feeds.
This commit is contained in:
parent
3eef4ee739
commit
551c86d6b4
@ -13,7 +13,7 @@
|
|||||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
''' E-book management software'''
|
''' E-book management software'''
|
||||||
__version__ = "0.3.94"
|
__version__ = "0.3.95"
|
||||||
__docformat__ = "epytext"
|
__docformat__ = "epytext"
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
__appname__ = 'libprs500'
|
__appname__ = 'libprs500'
|
||||||
|
@ -111,16 +111,14 @@ def process_profile(args, options, logger=None):
|
|||||||
profile['finalize'](profile)
|
profile['finalize'](profile)
|
||||||
shutil.rmtree(tdir)
|
shutil.rmtree(tdir)
|
||||||
|
|
||||||
|
def main(args=sys.argv, logger=None):
|
||||||
|
|
||||||
def main(args=sys.argv):
|
|
||||||
parser = option_parser()
|
parser = option_parser()
|
||||||
options, args = parser.parse_args(args)
|
options, args = parser.parse_args(args)
|
||||||
if len(args) > 2:
|
if len(args) > 2:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
try:
|
try:
|
||||||
process_profile(args, options)
|
process_profile(args, options, logger=logger)
|
||||||
except CommandLineError, err:
|
except CommandLineError, err:
|
||||||
print >>sys.stderr, err
|
print >>sys.stderr, err
|
||||||
return 0
|
return 0
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
UI = main_ui.py dialogs/metadata_single_ui.py dialogs/metadata_bulk_ui.py dialogs/jobs_ui.py
|
UI = main_ui.py dialogs/metadata_single_ui.py dialogs/metadata_bulk_ui.py dialogs/jobs_ui.py dialogs/conversion_error_ui.py
|
||||||
RC = images_rc.pyc
|
RC = images_rc.pyc
|
||||||
|
|
||||||
%_ui.py : %.ui
|
%_ui.py : %.ui
|
||||||
|
29
src/libprs500/gui2/dialogs/conversion_error.py
Normal file
29
src/libprs500/gui2/dialogs/conversion_error.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
|
||||||
|
## This program is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License along
|
||||||
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
''''''
|
||||||
|
|
||||||
|
from libprs500.gui2.dialogs import Dialog
|
||||||
|
from libprs500.gui2.dialogs.conversion_error_ui import Ui_ConversionErrorDialog
|
||||||
|
|
||||||
|
class ConversionErrorDialog(Dialog, Ui_ConversionErrorDialog):
|
||||||
|
|
||||||
|
def __init__(self, window, title, html):
|
||||||
|
Ui_ConversionErrorDialog.__init__(self)
|
||||||
|
Dialog.__init__(self, window)
|
||||||
|
self.setupUi(self.dialog)
|
||||||
|
html = '<html><body>' + html + '</body></html>'
|
||||||
|
self.dialog.setWindowTitle(title)
|
||||||
|
self.text.setHtml(html)
|
||||||
|
self.dialog.show()
|
51
src/libprs500/gui2/dialogs/conversion_error.ui
Normal file
51
src/libprs500/gui2/dialogs/conversion_error.ui
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<class>ConversionErrorDialog</class>
|
||||||
|
<widget class="QDialog" name="ConversionErrorDialog" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>658</width>
|
||||||
|
<height>515</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>ERROR</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon" >
|
||||||
|
<iconset resource="../images.qrc" >:/library</iconset>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" >
|
||||||
|
<item row="0" column="0" >
|
||||||
|
<widget class="QLabel" name="label" >
|
||||||
|
<property name="text" >
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap" >
|
||||||
|
<pixmap resource="../images.qrc" >:/images/dialog_error.svg</pixmap>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item rowspan="2" row="0" column="1" >
|
||||||
|
<widget class="QTextBrowser" name="text" />
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" >
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../images.qrc" />
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -1,6 +1,7 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/" >
|
<qresource prefix="/" >
|
||||||
<file>images/book.svg</file>
|
<file>images/book.svg</file>
|
||||||
|
<file>images/news.svg</file>
|
||||||
<file>images/clear_left.svg</file>
|
<file>images/clear_left.svg</file>
|
||||||
<file>images/dialog_error.svg</file>
|
<file>images/dialog_error.svg</file>
|
||||||
<file>images/dialog_warning.svg</file>
|
<file>images/dialog_warning.svg</file>
|
||||||
@ -33,5 +34,8 @@
|
|||||||
<file>images/sd.svg</file>
|
<file>images/sd.svg</file>
|
||||||
<file>images/sync.svg</file>
|
<file>images/sync.svg</file>
|
||||||
<file>images/trash.svg</file>
|
<file>images/trash.svg</file>
|
||||||
|
<file>images/news/bbc.png</file>
|
||||||
|
<file>images/news/newsweek.png</file>
|
||||||
|
<file>images/news/nytimes.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
2826
src/libprs500/gui2/images/news.svg
Normal file
2826
src/libprs500/gui2/images/news.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 109 KiB |
BIN
src/libprs500/gui2/images/news/bbc.png
Normal file
BIN
src/libprs500/gui2/images/news/bbc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 146 B |
BIN
src/libprs500/gui2/images/news/newsweek.png
Normal file
BIN
src/libprs500/gui2/images/news/newsweek.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
BIN
src/libprs500/gui2/images/news/nytimes.png
Normal file
BIN
src/libprs500/gui2/images/news/nytimes.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 866 B |
1961
src/libprs500/gui2/images/save.svg
Normal file
1961
src/libprs500/gui2/images/save.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 58 KiB |
@ -12,7 +12,7 @@
|
|||||||
## You should have received a copy of the GNU General Public License along
|
## You should have received a copy of the GNU General Public License along
|
||||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
import traceback, textwrap
|
import traceback, textwrap, logging, cStringIO
|
||||||
|
|
||||||
from PyQt4.QtCore import QAbstractTableModel, QMutex, QObject, SIGNAL, Qt, \
|
from PyQt4.QtCore import QAbstractTableModel, QMutex, QObject, SIGNAL, Qt, \
|
||||||
QVariant, QThread, QModelIndex
|
QVariant, QThread, QModelIndex
|
||||||
@ -41,7 +41,23 @@ class Job(QThread):
|
|||||||
self.mutex = mutex
|
self.mutex = mutex
|
||||||
self.result = None
|
self.result = None
|
||||||
self.percent_done = 0
|
self.percent_done = 0
|
||||||
|
self.logger = logging.getLogger('Job #'+str(id))
|
||||||
|
self.logger.setLevel(logging.DEBUG)
|
||||||
|
self.log_dest = cStringIO.StringIO()
|
||||||
|
handler = logging.StreamHandler(self.log_dest)
|
||||||
|
handler.setLevel(logging.DEBUG)
|
||||||
|
handler.setFormatter(logging.Formatter('[%(levelname)s] %(filename)s:%(lineno)s: %(message)s'))
|
||||||
|
self.logger.addHandler(handler)
|
||||||
|
|
||||||
|
|
||||||
|
def progress_update(self, val):
|
||||||
|
self.percent_done = val
|
||||||
|
self.emit(SIGNAL('status_update(int, int)'), self.id, int(val))
|
||||||
|
|
||||||
|
class DeviceJob(Job):
|
||||||
|
'''
|
||||||
|
Jobs that involve communication with the device. Synchronous.
|
||||||
|
'''
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.mutex != None:
|
if self.mutex != None:
|
||||||
self.mutex.lock()
|
self.mutex.lock()
|
||||||
@ -58,17 +74,21 @@ class Job(QThread):
|
|||||||
self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||||
self.id, self.description, self.result, exception, last_traceback)
|
self.id, self.description, self.result, exception, last_traceback)
|
||||||
|
|
||||||
def progress_update(self, val):
|
|
||||||
self.percent_done = val
|
|
||||||
self.emit(SIGNAL('status_update(int, int)'), self.id, int(val))
|
|
||||||
|
|
||||||
class DeviceJob(Job):
|
|
||||||
'''
|
|
||||||
Jobs that involve communication with the device.
|
|
||||||
'''
|
|
||||||
def __init__(self, id, description, mutex, func, *args, **kwargs):
|
|
||||||
Job.__init__(self, id, description, mutex, func, *args, **kwargs)
|
|
||||||
|
|
||||||
|
class ConversionJob(Job):
|
||||||
|
''' Jobs that invlove conversion of content. Asynchronous. '''
|
||||||
|
def run(self):
|
||||||
|
last_traceback, exception = None, None
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
self.kwargs['logger'] = self.logger
|
||||||
|
self.result = self.func(*self.args, **self.kwargs)
|
||||||
|
except Exception, err:
|
||||||
|
exception = err
|
||||||
|
last_traceback = traceback.format_exc()
|
||||||
|
finally:
|
||||||
|
self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||||
|
self.id, self.description, self.result, exception, last_traceback, self.log_dest.getvalue())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -123,6 +143,17 @@ class JobManager(QAbstractTableModel):
|
|||||||
def has_jobs(self):
|
def has_jobs(self):
|
||||||
return len(self.jobs.values()) > 0
|
return len(self.jobs.values()) > 0
|
||||||
|
|
||||||
|
def run_conversion_job(self, slot, callable, *args, **kwargs):
|
||||||
|
desc = kwargs.pop('job_description', '')
|
||||||
|
job = self.create_job(ConversionJob, desc, None, callable, *args, **kwargs)
|
||||||
|
QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||||
|
self.job_done)
|
||||||
|
if slot:
|
||||||
|
QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||||
|
slot)
|
||||||
|
job.start()
|
||||||
|
return job.id
|
||||||
|
|
||||||
def run_device_job(self, slot, callable, *args, **kwargs):
|
def run_device_job(self, slot, callable, *args, **kwargs):
|
||||||
'''
|
'''
|
||||||
Run a job to communicate with the device.
|
Run a job to communicate with the device.
|
||||||
@ -213,7 +244,7 @@ class JobManager(QAbstractTableModel):
|
|||||||
status = 'Done'
|
status = 'Done'
|
||||||
return QVariant(status)
|
return QVariant(status)
|
||||||
if col == 2:
|
if col == 2:
|
||||||
p = str(job.percent_done) + r'%'
|
p = str(job.percent_done) + r'%' if job.percent_done > 0 else 'Unavailable'
|
||||||
return QVariant(p)
|
return QVariant(p)
|
||||||
if role == Qt.DecorationRole and col == 0:
|
if role == Qt.DecorationRole and col == 0:
|
||||||
return self.device_job_icon if isinstance(job, DeviceJob) else self.job_icon
|
return self.device_job_icon if isinstance(job, DeviceJob) else self.job_icon
|
||||||
|
@ -16,11 +16,14 @@ import os, sys, traceback, StringIO, textwrap
|
|||||||
|
|
||||||
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
|
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
|
||||||
QSettings, QVariant, QSize, QThread
|
QSettings, QVariant, QSize, QThread
|
||||||
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox
|
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox, \
|
||||||
|
QToolButton
|
||||||
from PyQt4.QtSvg import QSvgRenderer
|
from PyQt4.QtSvg import QSvgRenderer
|
||||||
|
|
||||||
from libprs500 import __version__, __appname__
|
from libprs500 import __version__, __appname__
|
||||||
|
from libprs500.ptempfile import PersistentTemporaryFile
|
||||||
from libprs500.ebooks.metadata.meta import get_metadata
|
from libprs500.ebooks.metadata.meta import get_metadata
|
||||||
|
from libprs500.ebooks.lrf.web.convert_from import main as web2lrf
|
||||||
from libprs500.devices.errors import FreeSpaceError
|
from libprs500.devices.errors import FreeSpaceError
|
||||||
from libprs500.devices.interface import Device
|
from libprs500.devices.interface import Device
|
||||||
from libprs500.gui2 import APP_TITLE, warning_dialog, choose_files, error_dialog, \
|
from libprs500.gui2 import APP_TITLE, warning_dialog, choose_files, error_dialog, \
|
||||||
@ -33,6 +36,7 @@ from libprs500.gui2.jobs import JobManager
|
|||||||
from libprs500.gui2.dialogs.metadata_single import MetadataSingleDialog
|
from libprs500.gui2.dialogs.metadata_single import MetadataSingleDialog
|
||||||
from libprs500.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
from libprs500.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
||||||
from libprs500.gui2.dialogs.jobs import JobsDialog
|
from libprs500.gui2.dialogs.jobs import JobsDialog
|
||||||
|
from libprs500.gui2.dialogs.conversion_error import ConversionErrorDialog
|
||||||
|
|
||||||
|
|
||||||
class Main(QObject, Ui_MainWindow):
|
class Main(QObject, Ui_MainWindow):
|
||||||
@ -57,6 +61,8 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
self.device_manager = None
|
self.device_manager = None
|
||||||
self.upload_memory = {}
|
self.upload_memory = {}
|
||||||
self.delete_memory = {}
|
self.delete_memory = {}
|
||||||
|
self.conversion_jobs = {}
|
||||||
|
self.persistent_files = []
|
||||||
self.default_thumbnail = None
|
self.default_thumbnail = None
|
||||||
self.device_error_dialog = error_dialog(self.window, 'Error communicating with device', ' ')
|
self.device_error_dialog = error_dialog(self.window, 'Error communicating with device', ' ')
|
||||||
self.device_error_dialog.setModal(Qt.NonModal)
|
self.device_error_dialog.setModal(Qt.NonModal)
|
||||||
@ -98,10 +104,19 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
QObject.connect(self.action_save, SIGNAL("triggered(bool)"), self.save_to_disk)
|
QObject.connect(self.action_save, SIGNAL("triggered(bool)"), self.save_to_disk)
|
||||||
self.action_sync.setMenu(sm)
|
self.action_sync.setMenu(sm)
|
||||||
self.action_edit.setMenu(md)
|
self.action_edit.setMenu(md)
|
||||||
self.tool_bar.addAction(self.action_sync)
|
nm = QMenu()
|
||||||
self.tool_bar.addAction(self.action_edit)
|
nm.addAction(QIcon(':/images/news/bbc.png'), 'BBC')
|
||||||
|
nm.addAction(QIcon(':/images/news/newsweek.png'), 'Newsweek')
|
||||||
|
nm.addAction(QIcon(':/images/news/nytimes.png'), 'New York Times')
|
||||||
|
QObject.connect(nm.actions()[0], SIGNAL('triggered(bool)'), self.fetch_news_bbc)
|
||||||
|
QObject.connect(nm.actions()[1], SIGNAL('triggered(bool)'), self.fetch_news_newsweek)
|
||||||
|
QObject.connect(nm.actions()[2], SIGNAL('triggered(bool)'), self.fetch_news_nytimes)
|
||||||
|
self.news_menu = nm
|
||||||
|
self.action_news.setMenu(nm)
|
||||||
|
self.tool_bar.widgetForAction(self.action_news).setPopupMode(QToolButton.InstantPopup)
|
||||||
|
self.tool_bar.widgetForAction(self.action_edit).setPopupMode(QToolButton.MenuButtonPopup)
|
||||||
|
self.tool_bar.widgetForAction(self.action_sync).setPopupMode(QToolButton.MenuButtonPopup)
|
||||||
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
|
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||||
|
|
||||||
####################### Library view ########################
|
####################### Library view ########################
|
||||||
self.library_view.set_database(self.database_path)
|
self.library_view.set_database(self.database_path)
|
||||||
for func, target in [
|
for func, target in [
|
||||||
@ -231,10 +246,16 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
filters=[('Books', BOOK_EXTENSIONS)])
|
filters=[('Books', BOOK_EXTENSIONS)])
|
||||||
if not books:
|
if not books:
|
||||||
return
|
return
|
||||||
|
to_device = self.stack.currentIndex() != 0
|
||||||
|
self._add_books(books, to_device)
|
||||||
|
if to_device:
|
||||||
|
self.status_bar.showMessage('Uploading books to device.', 2000)
|
||||||
|
|
||||||
|
def _add_books(self, paths, to_device):
|
||||||
on_card = False if self.stack.currentIndex() != 2 else True
|
on_card = False if self.stack.currentIndex() != 2 else True
|
||||||
# Get format and metadata information
|
# Get format and metadata information
|
||||||
formats, metadata, names, infos = [], [], [], []
|
formats, metadata, names, infos = [], [], [], []
|
||||||
for book in books:
|
for book in paths:
|
||||||
format = os.path.splitext(book)[1]
|
format = os.path.splitext(book)[1]
|
||||||
format = format[1:] if format else None
|
format = format[1:] if format else None
|
||||||
stream = open(book, 'rb')
|
stream = open(book, 'rb')
|
||||||
@ -244,16 +265,16 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
formats.append(format)
|
formats.append(format)
|
||||||
metadata.append(mi)
|
metadata.append(mi)
|
||||||
names.append(os.path.basename(book))
|
names.append(os.path.basename(book))
|
||||||
infos.append({'title':mi.title, 'authors':mi.author, 'cover':self.default_thumbnail})
|
infos.append({'title':mi.title, 'authors':mi.author,
|
||||||
|
'cover':self.default_thumbnail, 'tags':[]})
|
||||||
|
|
||||||
if self.stack.currentIndex() == 0:
|
if not to_device:
|
||||||
model = self.current_view().model()
|
model = self.current_view().model()
|
||||||
model.add_books(books, formats, metadata)
|
model.add_books(paths, formats, metadata)
|
||||||
model.resort()
|
model.resort()
|
||||||
model.research()
|
model.research()
|
||||||
else:
|
else:
|
||||||
self.upload_books(books, names, infos, on_card=on_card)
|
self.upload_books(paths, names, infos, on_card=on_card)
|
||||||
self.status_bar.showMessage('Adding books to device.', 2000)
|
|
||||||
|
|
||||||
def upload_books(self, files, names, metadata, on_card=False):
|
def upload_books(self, files, names, metadata, on_card=False):
|
||||||
'''
|
'''
|
||||||
@ -446,6 +467,39 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
self.device_job_exception(id, description, exception, formatted_traceback)
|
self.device_job_exception(id, description, exception, formatted_traceback)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
############################### Fetch news #################################
|
||||||
|
|
||||||
|
def fetch_news(self, profile, pretty):
|
||||||
|
pt = PersistentTemporaryFile(suffix='.lrf')
|
||||||
|
pt.close()
|
||||||
|
args = ['web2lrf', '-o', pt.name, profile]
|
||||||
|
id = self.job_manager.run_conversion_job(self.news_fetched, web2lrf, args=args,
|
||||||
|
job_description='Fetch news from '+pretty)
|
||||||
|
self.conversion_jobs[id] = (pt, 'lrf')
|
||||||
|
self.status_bar.showMessage('Fetching news from '+pretty, 2000)
|
||||||
|
|
||||||
|
def news_fetched(self, id, description, result, exception, formatted_traceback, log):
|
||||||
|
pt, fmt = self.conversion_jobs.pop(id)
|
||||||
|
if exception:
|
||||||
|
self.conversion_job_exception(id, description, exception, formatted_traceback, log)
|
||||||
|
return
|
||||||
|
to_device = self.device_connected and fmt in self.device_manager.device_class.FORMATS
|
||||||
|
self._add_books([pt.name], to_device)
|
||||||
|
if to_device:
|
||||||
|
self.status_bar.showMessage('News fetched. Uploading to device.', 2000)
|
||||||
|
self.persistent_files.append(pt)
|
||||||
|
|
||||||
|
def fetch_news_bbc(self, checked):
|
||||||
|
self.fetch_news('bbc', 'BBC')
|
||||||
|
|
||||||
|
def fetch_news_newsweek(self, checked):
|
||||||
|
self.fetch_news('newsweek', 'Newsweek')
|
||||||
|
|
||||||
|
def fetch_news_nytimes(self, checked):
|
||||||
|
self.fetch_news('nytimes', 'New York Times')
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
def location_selected(self, location):
|
def location_selected(self, location):
|
||||||
'''
|
'''
|
||||||
@ -492,6 +546,18 @@ class Main(QObject, Ui_MainWindow):
|
|||||||
self.device_error_dialog.setText(msg)
|
self.device_error_dialog.setText(msg)
|
||||||
self.device_error_dialog.show()
|
self.device_error_dialog.show()
|
||||||
|
|
||||||
|
def conversion_job_exception(self, id, description, exception, formatted_traceback, log):
|
||||||
|
print >>sys.stderr, 'Error in job:', description
|
||||||
|
print >>sys.stderr, log
|
||||||
|
print >>sys.stderr, exception
|
||||||
|
print >>sys.stderr, formatted_traceback
|
||||||
|
msg = u'<p><b>%s</b>: '%(exception.__class__.__name__,) + unicode(str(exception), 'utf8', 'replace') + u'</p>'
|
||||||
|
msg += u'<p>Failed to perform <b>job</b>: '+description
|
||||||
|
msg += u'<p>Detailed <b>traceback</b>:<pre>'
|
||||||
|
msg += formatted_traceback + '</pre>'
|
||||||
|
msg += '<p><b>Log:</b></p><pre>'
|
||||||
|
msg += log
|
||||||
|
ConversionErrorDialog(self.window, 'Conversion Error', msg)
|
||||||
|
|
||||||
|
|
||||||
def read_settings(self):
|
def read_settings(self):
|
||||||
|
@ -319,7 +319,12 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<addaction name="action_add" />
|
<addaction name="action_add" />
|
||||||
<addaction name="action_del" />
|
<addaction name="action_del" />
|
||||||
|
<addaction name="action_edit" />
|
||||||
|
<addaction name="separator" />
|
||||||
|
<addaction name="action_sync" />
|
||||||
<addaction name="action_save" />
|
<addaction name="action_save" />
|
||||||
|
<addaction name="separator" />
|
||||||
|
<addaction name="action_news" />
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar" >
|
<widget class="QStatusBar" name="statusBar" >
|
||||||
<property name="mouseTracking" >
|
<property name="mouseTracking" >
|
||||||
@ -387,6 +392,14 @@
|
|||||||
<string>Save to disk</string>
|
<string>Save to disk</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_news" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="images.qrc" >:/images/news.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Fetch news</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user