From 551c86d6b4d2f30c810f49bb283be071bad24a14 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 13 Aug 2007 05:32:02 +0000 Subject: [PATCH] Implemented GUI for news feeds. --- src/libprs500/__init__.py | 2 +- src/libprs500/ebooks/lrf/web/convert_from.py | 6 +- src/libprs500/gui2/Makefile | 2 +- .../gui2/dialogs/conversion_error.py | 29 + .../gui2/dialogs/conversion_error.ui | 51 + src/libprs500/gui2/images.qrc | 4 + src/libprs500/gui2/images/news.svg | 2826 +++++++++++++++++ src/libprs500/gui2/images/news/bbc.png | Bin 0 -> 146 bytes src/libprs500/gui2/images/news/newsweek.png | Bin 0 -> 9911 bytes src/libprs500/gui2/images/news/nytimes.png | Bin 0 -> 866 bytes src/libprs500/gui2/images/save.svg | 1961 ++++++++++++ src/libprs500/gui2/jobs.py | 61 +- src/libprs500/gui2/main.py | 90 +- src/libprs500/gui2/main.ui | 13 + 14 files changed, 5012 insertions(+), 33 deletions(-) create mode 100644 src/libprs500/gui2/dialogs/conversion_error.py create mode 100644 src/libprs500/gui2/dialogs/conversion_error.ui create mode 100644 src/libprs500/gui2/images/news.svg create mode 100644 src/libprs500/gui2/images/news/bbc.png create mode 100644 src/libprs500/gui2/images/news/newsweek.png create mode 100644 src/libprs500/gui2/images/news/nytimes.png create mode 100644 src/libprs500/gui2/images/save.svg diff --git a/src/libprs500/__init__.py b/src/libprs500/__init__.py index e5413c8ddc..8fbe6f627e 100644 --- a/src/libprs500/__init__.py +++ b/src/libprs500/__init__.py @@ -13,7 +13,7 @@ ## with this program; if not, write to the Free Software Foundation, Inc., ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ''' E-book management software''' -__version__ = "0.3.94" +__version__ = "0.3.95" __docformat__ = "epytext" __author__ = "Kovid Goyal " __appname__ = 'libprs500' diff --git a/src/libprs500/ebooks/lrf/web/convert_from.py b/src/libprs500/ebooks/lrf/web/convert_from.py index 11690b0e60..59a90f24e3 100644 --- a/src/libprs500/ebooks/lrf/web/convert_from.py +++ b/src/libprs500/ebooks/lrf/web/convert_from.py @@ -111,16 +111,14 @@ def process_profile(args, options, logger=None): profile['finalize'](profile) shutil.rmtree(tdir) - - -def main(args=sys.argv): +def main(args=sys.argv, logger=None): parser = option_parser() options, args = parser.parse_args(args) if len(args) > 2: parser.print_help() return 1 try: - process_profile(args, options) + process_profile(args, options, logger=logger) except CommandLineError, err: print >>sys.stderr, err return 0 diff --git a/src/libprs500/gui2/Makefile b/src/libprs500/gui2/Makefile index 9575097fc9..96620113f5 100644 --- a/src/libprs500/gui2/Makefile +++ b/src/libprs500/gui2/Makefile @@ -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 %_ui.py : %.ui diff --git a/src/libprs500/gui2/dialogs/conversion_error.py b/src/libprs500/gui2/dialogs/conversion_error.py new file mode 100644 index 0000000000..325481bf86 --- /dev/null +++ b/src/libprs500/gui2/dialogs/conversion_error.py @@ -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 + '' + self.dialog.setWindowTitle(title) + self.text.setHtml(html) + self.dialog.show() \ No newline at end of file diff --git a/src/libprs500/gui2/dialogs/conversion_error.ui b/src/libprs500/gui2/dialogs/conversion_error.ui new file mode 100644 index 0000000000..38d215269d --- /dev/null +++ b/src/libprs500/gui2/dialogs/conversion_error.ui @@ -0,0 +1,51 @@ + + ConversionErrorDialog + + + + 0 + 0 + 658 + 515 + + + + ERROR + + + :/library + + + + + + + + + :/images/dialog_error.svg + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/src/libprs500/gui2/images.qrc b/src/libprs500/gui2/images.qrc index e968fb9e64..0d7f268364 100644 --- a/src/libprs500/gui2/images.qrc +++ b/src/libprs500/gui2/images.qrc @@ -1,6 +1,7 @@ images/book.svg + images/news.svg images/clear_left.svg images/dialog_error.svg images/dialog_warning.svg @@ -33,5 +34,8 @@ images/sd.svg images/sync.svg images/trash.svg + images/news/bbc.png + images/news/newsweek.png + images/news/nytimes.png diff --git a/src/libprs500/gui2/images/news.svg b/src/libprs500/gui2/images/news.svg new file mode 100644 index 0000000000..38016738f5 --- /dev/null +++ b/src/libprs500/gui2/images/news.svg @@ -0,0 +1,2826 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Oxygen team + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libprs500/gui2/images/news/bbc.png b/src/libprs500/gui2/images/news/bbc.png new file mode 100644 index 0000000000000000000000000000000000000000..7255a175bf1e7175cb23fd54c5f32a620d91491f GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx?BpA#)4xIr~OiAAEE({E-dX6TJX7F_Nb6Mw<&;$ThEhIMp literal 0 HcmV?d00001 diff --git a/src/libprs500/gui2/images/news/newsweek.png b/src/libprs500/gui2/images/news/newsweek.png new file mode 100644 index 0000000000000000000000000000000000000000..987c946552f64f5faa627b7edaaff64c514322d1 GIT binary patch literal 9911 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 literal 0 HcmV?d00001 diff --git a/src/libprs500/gui2/images/news/nytimes.png b/src/libprs500/gui2/images/news/nytimes.png new file mode 100644 index 0000000000000000000000000000000000000000..17282300fe05efae4f31092f9e95ed0e567f5c5b GIT binary patch literal 866 zcmV-o1D*VdP)$VVb6@s^8z=@k|s&0Dxf_0)Q;bVHkEgo%Qwg$;rvZ#l=#o^#1-1 z0GF4StE;PsC!Tu_4@jHeSJMXKF%1Mo10r& zTGBKvkw{3AIgUdJNvG2o zpBn_h-`}5M7y|(GQcCH^$A@7U+uPf=ZL6vpMG+wc0U!v1o}Qk^$Hy=XUDy5j z`5}Z5LNrY)m&?!3&zVeya~?$zW9)xQ05CW>D2igM)p~n-^E_{6W@dSLIh{@uLUwj` z1VKPVQ4|pXR8?)YT0=uanx^&j^%aZ7VzGE~axykHW?5FDP%ur?G)+XLlp+B5zMsqG z0O088==b-x+wGRi<$ArowzgKU*FQf$bzSf6?Trh9olYl}N(qACIL^Yt!p+SMA~MD* zmCD)K82}s}9*&NV%CZaq0D$po5Ck#h{QUga*Vp;^d8JaRR;w>BFS@Sx_xH!2ZnxVA z0G4GXlSxHU;xx0_tgh>uo0}UO8^goHvAHBkjInGs`wxD}VKhla=dAz$02+E!SafP| zWoJ5LZ)|UJb8ul}WdHzp+A{(G05bqHi8v!Q0000fdQ@0+YH(#|I&)!daBOLAXDw!7 sV{~tF004N}GpaDsF|07uF|05I01<-%>2t65LjV8(07*qoM6N<$g3L9A;{X5v literal 0 HcmV?d00001 diff --git a/src/libprs500/gui2/images/save.svg b/src/libprs500/gui2/images/save.svg new file mode 100644 index 0000000000..af62235cfc --- /dev/null +++ b/src/libprs500/gui2/images/save.svg @@ -0,0 +1,1961 @@ + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libprs500/gui2/jobs.py b/src/libprs500/gui2/jobs.py index d76f8663a0..43073016be 100644 --- a/src/libprs500/gui2/jobs.py +++ b/src/libprs500/gui2/jobs.py @@ -12,7 +12,7 @@ ## 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. -import traceback, textwrap +import traceback, textwrap, logging, cStringIO from PyQt4.QtCore import QAbstractTableModel, QMutex, QObject, SIGNAL, Qt, \ QVariant, QThread, QModelIndex @@ -41,12 +41,28 @@ class Job(QThread): self.mutex = mutex self.result = None 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): if self.mutex != None: self.mutex.lock() last_traceback, exception = None, None - try: + try: try: self.result = self.func(self.progress_update, *self.args, **self.kwargs) except Exception, err: @@ -57,20 +73,24 @@ class Job(QThread): self.mutex.unlock() self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), 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()) + + class JobManager(QAbstractTableModel): @@ -123,6 +143,17 @@ class JobManager(QAbstractTableModel): def has_jobs(self): 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): ''' Run a job to communicate with the device. @@ -213,7 +244,7 @@ class JobManager(QAbstractTableModel): status = 'Done' return QVariant(status) 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) if role == Qt.DecorationRole and col == 0: return self.device_job_icon if isinstance(job, DeviceJob) else self.job_icon diff --git a/src/libprs500/gui2/main.py b/src/libprs500/gui2/main.py index fc0b2926a4..c9474ff46a 100644 --- a/src/libprs500/gui2/main.py +++ b/src/libprs500/gui2/main.py @@ -16,11 +16,14 @@ import os, sys, traceback, StringIO, textwrap from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \ 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 libprs500 import __version__, __appname__ +from libprs500.ptempfile import PersistentTemporaryFile 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.interface import Device 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_bulk import MetadataBulkDialog from libprs500.gui2.dialogs.jobs import JobsDialog +from libprs500.gui2.dialogs.conversion_error import ConversionErrorDialog class Main(QObject, Ui_MainWindow): @@ -57,6 +61,8 @@ class Main(QObject, Ui_MainWindow): self.device_manager = None self.upload_memory = {} self.delete_memory = {} + self.conversion_jobs = {} + self.persistent_files = [] self.default_thumbnail = None self.device_error_dialog = error_dialog(self.window, 'Error communicating with device', ' ') 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) self.action_sync.setMenu(sm) self.action_edit.setMenu(md) - self.tool_bar.addAction(self.action_sync) - self.tool_bar.addAction(self.action_edit) - self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu) - + nm = QMenu() + 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) ####################### Library view ######################## self.library_view.set_database(self.database_path) for func, target in [ @@ -231,10 +246,16 @@ class Main(QObject, Ui_MainWindow): filters=[('Books', BOOK_EXTENSIONS)]) if not books: 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 # Get format and metadata information formats, metadata, names, infos = [], [], [], [] - for book in books: + for book in paths: format = os.path.splitext(book)[1] format = format[1:] if format else None stream = open(book, 'rb') @@ -244,16 +265,16 @@ class Main(QObject, Ui_MainWindow): formats.append(format) metadata.append(mi) 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.add_books(books, formats, metadata) + model.add_books(paths, formats, metadata) model.resort() model.research() else: - self.upload_books(books, names, infos, on_card=on_card) - self.status_bar.showMessage('Adding books to device.', 2000) + self.upload_books(paths, names, infos, on_card=on_card) 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) 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): ''' @@ -491,7 +545,19 @@ class Main(QObject, Ui_MainWindow): msg += self.wrap_traceback(formatted_traceback) self.device_error_dialog.setText(msg) 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'

%s: '%(exception.__class__.__name__,) + unicode(str(exception), 'utf8', 'replace') + u'

' + msg += u'

Failed to perform job: '+description + msg += u'

Detailed traceback:

'
+        msg += formatted_traceback + '
' + msg += '

Log:

'
+        msg += log
+        ConversionErrorDialog(self.window, 'Conversion Error', msg)
         
     
     def read_settings(self):
diff --git a/src/libprs500/gui2/main.ui b/src/libprs500/gui2/main.ui
index afc08087f2..39780763fe 100644
--- a/src/libprs500/gui2/main.ui
+++ b/src/libprs500/gui2/main.ui
@@ -319,7 +319,12 @@
    
    
    
+   
+   
+   
    
+   
+   
   
   
    
@@ -387,6 +392,14 @@
     Save to disk
    
   
+  
+   
+    :/images/news.svg
+   
+   
+    Fetch news
+   
+