Improved user feedback when downloading covers

This commit is contained in:
Kovid Goyal 2009-03-19 19:52:53 -07:00
parent 40a4753592
commit 6fbe65b598
4 changed files with 111 additions and 67 deletions

View File

@ -273,7 +273,6 @@ File ::C49805D2-C0B8-01C4-DF6F-674D9C0BFD15 -name IM_MOD_RL_viff_.dll -parent 8E
File ::1B9F2F00-20A5-B207-5A80-8F75470286AD -name txt2lrf.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::826F1915-9F97-59DD-6637-3EEC0744A79C -name IM_MOD_RL_ps2_.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::519A6618-8A1F-93A5-93B4-6EEF5A4A3DE9 -name comic2pdf.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::B0CEAA35-52BF-0DE0-BAC7-7B23157E29BD -name isbndb.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::A5F23791-BCDC-A997-4941-5D1F2F227E6D -name type.xml -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::0A1C107A-C0AA-3ED6-4F37-A6894386DCBE -name IM_MOD_RL_ps3_.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::EEBA64E7-6509-EBAF-3E23-1A203216F39A -name epub2lrf.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
@ -284,7 +283,6 @@ File ::EA37C1C2-57BB-4E7A-C004-0010D79142C2 -name IM_MOD_RL_fits_.dll -parent 8E
File ::05F5C10D-6988-F1F4-A486-86C96DB20302 -name pywintypes26.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::0137A2B1-EB94-EB26-7295-0C7CD941A1DF -name IM_MOD_RL_histogram_.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::7F199A1F-4FA4-2ABA-DED3-36ECF3C089CA -name epub2lrf.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::F9F112C9-B61B-E041-1A9D-47641B047135 -name isbndb.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::CF6398D8-2140-53CF-1DA6-421A82E92621 -name any2epub.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::8DFA6C69-360D-FA63-7FF9-860E3DB00B19 -name any2lrf.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::5BB7579D-9183-412C-81F8-B411B07C57B3 -name IM_MOD_RL_pnm_.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
@ -544,6 +542,8 @@ File ::325F545D-30A8-08DA-74F0-AC1244F6C1D9 -name IM_MOD_RL_vid_.dll -parent 8E5
File ::24238371-77D0-0A8F-35D1-498A5FCC1B0D -name IM_MOD_RL_rla_.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::6F5D62F3-5E63-0753-364C-01CAAF1002E0 -name IM_MOD_RL_magick_.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::9FDAC308-5D4F-A865-A09A-9FBF48162A47 -name IM_MOD_RL_djvu_.dll -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::5D748040-5973-EFF1-41FC-B424636C642E -name fetch-ebook-metadata.exe.local -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
File ::8B8655B8-3823-AA02-1CDA-02F5AD4677C0 -name fetch-ebook-metadata.exe -parent 8E5D85A4-7608-47A1-CF7C-309060D5FF40
Component ::F6829AB7-9F66-4CEE-CA0E-21F54C6D3609 -setup Install -active Yes -platforms {AIX-ppc FreeBSD-4-x86 FreeBSD-x86 HPUX-hppa Linux-x86 Solaris-sparc Windows} -name Main -parent Components
SetupType ::D9ADE41C-B744-690C-2CED-CF826BF03D2E -setup Install -active Yes -platforms {AIX-ppc FreeBSD-4-x86 FreeBSD-x86 HPUX-hppa Linux-x86 Solaris-sparc Windows} -name Typical -parent SetupTypes

View File

@ -8,10 +8,11 @@ import time
from PyQt4.QtCore import Qt, QObject, SIGNAL, QVariant, QThread, \
QAbstractTableModel, QCoreApplication, QTimer
from PyQt4.QtGui import QDialog, QItemSelectionModel, QWidget, QLabel, QMovie
from PyQt4.QtGui import QDialog, QItemSelectionModel
from calibre.gui2.dialogs.fetch_metadata_ui import Ui_FetchMetadata
from calibre.gui2 import error_dialog, NONE, info_dialog, warning_dialog
from calibre.gui2.widgets import ProgressIndicator
from calibre.utils.config import prefs
class Fetcher(QThread):
@ -30,41 +31,7 @@ class Fetcher(QThread):
self.publisher, self.isbn,
self.key if self.key else None)
class ProgressIndicator(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
self.setGeometry(0, 0, 300, 350)
self.movie = QMovie(':/images/jobs-animated.mng')
self.ml = QLabel(self)
self.ml.setMovie(self.movie)
self.movie.start()
self.movie.setPaused(True)
self.status = QLabel(self)
self.status.setWordWrap(True)
self.status.setAlignment(Qt.AlignHCenter|Qt.AlignTop)
self.status.font().setBold(True)
self.status.font().setPointSize(self.font().pointSize()+6)
self.setVisible(False)
def start(self, msg=''):
view = self.parent()
pwidth, pheight = view.size().width(), view.size().height()
self.resize(pwidth, min(pheight, 250))
self.move(0, (pheight-self.size().height())/2.)
self.ml.resize(self.ml.sizeHint())
self.ml.move(int((self.size().width()-self.ml.size().width())/2.), 0)
self.status.resize(self.size().width(), self.size().height()-self.ml.size().height()-10)
self.status.move(0, self.ml.size().height()+10)
self.status.setText(msg)
self.setVisible(True)
self.movie.setPaused(False)
def stop(self):
if self.movie.state() == self.movie.Running:
self.movie.setPaused(True)
self.setVisible(False)
class Matches(QAbstractTableModel):
def __init__(self, matches):
@ -173,7 +140,7 @@ class FetchMetadata(QDialog, Ui_FetchMetadata):
self._hangcheck = QTimer(self)
self.connect(self._hangcheck, SIGNAL('timeout()'), self.hangcheck)
self.start_time = time.time()
self._hangcheck.start()
self._hangcheck.start(100)
def hangcheck(self):
if not (self.fetcher.isFinished() or time.time() - self.start_time > 75):

View File

@ -4,9 +4,9 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
The dialog used to edit meta information for a book as well as
add/remove formats
'''
import os
import os, time, traceback
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog, QCompleter
@ -16,14 +16,35 @@ from calibre.gui2.dialogs.metadata_single_ui import Ui_MetadataSingleDialog
from calibre.gui2.dialogs.fetch_metadata import FetchMetadata
from calibre.gui2.dialogs.tag_editor import TagEditor
from calibre.gui2.dialogs.password import PasswordDialog
from calibre.gui2.widgets import ProgressIndicator
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.ebooks.metadata import authors_to_sort_string, string_to_authors, authors_to_string
from calibre.ebooks.metadata.library_thing import login, cover_from_isbn, LibraryThingError
from calibre.ebooks.metadata.library_thing import login, cover_from_isbn
from calibre import islinux
from calibre.ebooks.metadata.meta import get_metadata
from calibre.utils.config import prefs
from calibre.customize.ui import run_plugins_on_import
class CoverFetcher(QThread):
def __init__(self, username, password, isbn, timeout):
self.username = username
self.password = password
self.timeout = timeout
self.isbn = isbn
QThread.__init__(self)
self.exception = self.traceback = self.cover_data = None
def run(self):
try:
login(self.username, self.password, force=False)
self.cover_data = cover_from_isbn(self.isbn, timeout=self.timeout)[0]
except Exception, e:
self.exception = e
self.traceback = traceback.format_exc()
class Format(QListWidgetItem):
def __init__(self, parent, ext, size, path=None):
self.path = path
@ -172,6 +193,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter)
self.splitter.setStretchFactor(100, 1)
self.db = db
self.pi = ProgressIndicator(self)
self.accepted_callback = accepted_callback
self.id = db.id(row)
self.row = row
@ -338,32 +360,51 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
return
self.fetch_cover_button.setEnabled(False)
self.setCursor(Qt.WaitCursor)
QCoreApplication.instance().processEvents()
try:
login(d.username(), d.password(), force=False)
cover_data = cover_from_isbn(isbn, timeout=self.timeout)[0]
pix = QPixmap()
pix.loadFromData(cover_data)
if pix.isNull():
error_dialog(self.window, _('Bad cover'),
_('The cover is not a valid picture')).exec_()
else:
self.cover.setPixmap(pix)
self.cover_changed = True
self.cpixmap = pix
except LibraryThingError, err:
error_dialog(self, _('Cannot fetch cover'),
_('<b>Could not fetch cover.</b><br/>')+repr(err)).exec_()
finally:
self.fetch_cover_button.setEnabled(True)
self.unsetCursor()
self.cover_fetcher = CoverFetcher(d.username(), d.password(), isbn,
self.timeout)
self.cover_fetcher.start()
self._hangcheck = QTimer(self)
self.connect(self._hangcheck, SIGNAL('timeout()'), self.hangcheck)
self.cf_start_time = time.time()
self.pi.start(_('Downloading cover...'))
self._hangcheck.start(100)
else:
error_dialog(self, _('Cannot fetch cover'),
_('You must specify the ISBN identifier for this book.')).exec_()
_('You must specify the ISBN identifier for this book.')).exec_()
def hangcheck(self):
if not (self.cover_fetcher.isFinished() or time.time()-self.cf_start_time > 150):
return
self._hangcheck.stop()
try:
if self.cover_fetcher.isRunning():
self.cover_fetcher.terminate()
error_dialog(self, _('Cannot fetch cover'),
_('<b>Could not fetch cover.</b><br/>')+
_('The download timed out.')).exec_()
return
if self.cover_fetcher.exception is not None:
err = self.cover_fetcher.exception
error_dialog(self, _('Cannot fetch cover'),
_('<b>Could not fetch cover.</b><br/>')+repr(err)).exec_()
return
pix = QPixmap()
pix.loadFromData(self.cover_fetcher.cover_data)
if pix.isNull():
error_dialog(self.window, _('Bad cover'),
_('The cover is not a valid picture')).exec_()
else:
self.cover.setPixmap(pix)
self.cover_changed = True
self.cpixmap = pix
finally:
self.fetch_cover_button.setEnabled(True)
self.unsetCursor()
self.pi.stop()
def fetch_metadata(self):
isbn = qstring_to_unicode(self.isbn.text())
title = qstring_to_unicode(self.title.text())

View File

@ -7,9 +7,9 @@ import re, os, traceback
from PyQt4.QtGui import QListView, QIcon, QFont, QLabel, QListWidget, \
QListWidgetItem, QTextCharFormat, QApplication, \
QSyntaxHighlighter, QCursor, QColor, QWidget, QDialog, \
QPixmap
QPixmap, QMovie
from PyQt4.QtCore import QAbstractListModel, QVariant, Qt, SIGNAL, \
QObject, QRegExp, QString, QSettings, QSize
QObject, QRegExp, QSettings, QSize
from calibre.gui2.jobs2 import DetailView
from calibre.gui2 import human_readable, NONE, TableView, \
@ -21,6 +21,42 @@ from calibre.ebooks.metadata.meta import metadata_from_filename
from calibre.utils.config import prefs
from calibre.gui2.dialogs.warning_ui import Ui_Dialog as Ui_WarningDialog
class ProgressIndicator(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
self.setGeometry(0, 0, 300, 350)
self.movie = QMovie(':/images/jobs-animated.mng')
self.ml = QLabel(self)
self.ml.setMovie(self.movie)
self.movie.start()
self.movie.setPaused(True)
self.status = QLabel(self)
self.status.setWordWrap(True)
self.status.setAlignment(Qt.AlignHCenter|Qt.AlignTop)
self.status.font().setBold(True)
self.status.font().setPointSize(self.font().pointSize()+6)
self.setVisible(False)
def start(self, msg=''):
view = self.parent()
pwidth, pheight = view.size().width(), view.size().height()
self.resize(pwidth, min(pheight, 250))
self.move(0, (pheight-self.size().height())/2.)
self.ml.resize(self.ml.sizeHint())
self.ml.move(int((self.size().width()-self.ml.size().width())/2.), 0)
self.status.resize(self.size().width(), self.size().height()-self.ml.size().height()-10)
self.status.move(0, self.ml.size().height()+10)
self.status.setText(msg)
self.setVisible(True)
self.movie.setPaused(False)
def stop(self):
if self.movie.state() == self.movie.Running:
self.movie.setPaused(True)
self.setVisible(False)
class WarningDialog(QDialog, Ui_WarningDialog):
def __init__(self, title, msg, details, parent=None):