diff --git a/installer/windows/calibre/calibre.mpi b/installer/windows/calibre/calibre.mpi index ee7ab53455..8073c45f29 100644 --- a/installer/windows/calibre/calibre.mpi +++ b/installer/windows/calibre/calibre.mpi @@ -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 diff --git a/src/calibre/gui2/dialogs/fetch_metadata.py b/src/calibre/gui2/dialogs/fetch_metadata.py index 99d454fa7e..8531452043 100644 --- a/src/calibre/gui2/dialogs/fetch_metadata.py +++ b/src/calibre/gui2/dialogs/fetch_metadata.py @@ -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): diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index 694fec21f3..c1f45128b2 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -4,9 +4,9 @@ __copyright__ = '2008, Kovid Goyal ' 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'), - _('Could not fetch cover.
')+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'), + _('Could not fetch cover.
')+ + _('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'), + _('Could not fetch cover.
')+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()) diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index caf2011a75..c6fa1723bd 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -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):