diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index b07be1904b..bd1e85d8e8 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -10,7 +10,7 @@ from functools import partial from PyQt4.Qt import Qt, QMenu, QModelIndex, QTimer -from calibre.gui2 import error_dialog, config, Dispatcher +from calibre.gui2 import error_dialog, config, Dispatcher, question_dialog from calibre.gui2.dialogs.metadata_single import MetadataSingleDialog from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog from calibre.gui2.dialogs.confirm_delete import confirm @@ -79,6 +79,7 @@ class EditMetadataAction(InterfaceAction): self.qaction.setEnabled(enabled) self.action_merge.setEnabled(enabled) + # Download metadata {{{ def download_metadata(self, ids=None): if ids is None: rows = self.gui.library_view.selectionModel().selectedRows() @@ -89,14 +90,73 @@ class EditMetadataAction(InterfaceAction): ids = [db.id(row.row()) for row in rows] from calibre.gui2.metadata.bulk_download2 import start_download start_download(self.gui, ids, - Dispatcher(self.bulk_metadata_downloaded)) + Dispatcher(self.metadata_downloaded)) - def bulk_metadata_downloaded(self, job): + def metadata_downloaded(self, job): if job.failed: self.gui.job_exception(job, dialog_title=_('Failed to download metadata')) return - from calibre.gui2.metadata.bulk_download2 import proceed - proceed(self.gui, job) + from calibre.gui2.metadata.bulk_download2 import get_job_details + id_map, failed_ids, failed_covers, all_failed, det_msg = \ + get_job_details(job) + if all_failed: + return error_dialog(self.gui, _('Download failed'), + _('Failed to download metadata or covers for any of the %d' + ' book(s).') % len(id_map), det_msg=det_msg, show=True) + + self.gui.status_bar.show_message(_('Metadata download completed'), 3000) + + msg = '
' + _('Finished downloading metadata for %d book(s). ' + 'Proceed with updating the metadata in your library?')%len(id_map) + + show_copy_button = False + if failed_ids or failed_covers: + show_copy_button = True + msg += '
'+_('Could not download metadata and/or covers for %d of the books. Click' + ' "Show details" to see which books.')%len(failed_ids) + + payload = (id_map, failed_ids, failed_covers) + from calibre.gui2.dialogs.message_box import ProceedNotification + p = ProceedNotification(payload, job.html_details, + _('Download log'), _('Download complete'), msg, + det_msg=det_msg, show_copy_button=show_copy_button, + parent=self.gui) + p.proceed.connect(self.apply_downloaded_metadata) + p.show() + + def apply_downloaded_metadata(self, payload): + id_map, failed_ids, failed_covers = payload + id_map = dict([(k, v) for k, v in id_map.iteritems() if k not in + failed_ids]) + if not id_map: + return + + modified = set() + db = self.gui.current_db + + for i, mi in id_map.iteritems(): + lm = db.metadata_last_modified(i, index_is_id=True) + if lm > mi.last_modified: + title = db.title(i, index_is_id=True) + authors = db.authors(i, index_is_id=True) + if authors: + authors = [x.replace('|', ',') for x in authors.split(',')] + title += ' - ' + authors_to_string(authors) + modified.add(title) + + if modified: + from calibre.utils.icu import lower + + modified = sorted(modified, key=lower) + if not question_dialog(self.gui, _('Some books changed'), '
'+
+ _('The metadata for some books in your library has'
+ ' changed since you started the download. If you'
+ ' proceed, some of those changes may be overwritten. '
+ 'Click "Show details" to see the list of changed books. '
+ 'Do you want to proceed?'), det_msg='\n'.join(modified)):
+ return
+
+ self.apply_metadata_changes(id_map)
def download_metadata_old(self, checked, covers=True, set_metadata=True,
set_social_metadata=None):
@@ -141,6 +201,7 @@ class EditMetadataAction(InterfaceAction):
x.updated, cr)
if self.gui.cover_flow:
self.gui.cover_flow.dataChanged()
+ # }}}
def edit_metadata(self, checked, bulk=None):
'''
@@ -467,8 +528,8 @@ class EditMetadataAction(InterfaceAction):
self.gui.upload_collections(model.db, view=view, oncard=oncard)
view.reset()
- def apply_metadata_changes(self, id_map,
- title=_('Applying changed metadata'), msg=''):
+ # Apply bulk metadata changes {{{
+ def apply_metadata_changes(self, id_map, title=None, msg=''):
'''
Apply the metadata changes in id_map to the database synchronously
id_map must be a mapping of ids to Metadata objects. Set any fields you
@@ -476,6 +537,8 @@ class EditMetadataAction(InterfaceAction):
that is to create a metadata object as Metadata(_('Unknown')) and then
only set the fields you want changed on this object.
'''
+ if title is None:
+ title = _('Applying changed metadata')
self.apply_id_map = list(id_map.iteritems())
self.apply_current_idx = 0
self.apply_failures = []
@@ -549,3 +612,5 @@ class EditMetadataAction(InterfaceAction):
self.apply_id_map = []
self.apply_pd = None
+ # }}}
+
diff --git a/src/calibre/gui2/dialogs/message_box.py b/src/calibre/gui2/dialogs/message_box.py
index 945d50de4e..56e0065f54 100644
--- a/src/calibre/gui2/dialogs/message_box.py
+++ b/src/calibre/gui2/dialogs/message_box.py
@@ -6,13 +6,13 @@ __copyright__ = '2011, Kovid Goyal '+
- _('The metadata for some books in your library has'
- ' changed since you started the download. If you'
- ' proceed, some of those changes may be overwritten. '
- 'Click "Show details" to see the list of changed books. '
- 'Do you want to proceed?'), det_msg='\n'.join(modified)):
- return
-
- gui.iactions['Edit Metadata'].apply_metadata_changes(id_map)
-
-def proceed(gui, job):
- gui.status_bar.show_message(_('Metadata download completed'), 3000)
+def get_job_details(job):
id_map, failed_ids, failed_covers, title_map, all_failed = job.result
det_msg = []
for i in failed_ids | failed_covers:
@@ -191,31 +113,7 @@ def proceed(gui, job):
title += (' ' + _('(Failed cover)'))
det_msg.append(title)
det_msg = '\n'.join(det_msg)
-
- if all_failed:
- q = error_dialog(gui, _('Download failed'),
- _('Failed to download metadata or covers for any of the %d'
- ' book(s).') % len(id_map), det_msg=det_msg)
- else:
- fmsg = ''
- if failed_ids or failed_covers:
- fmsg = ' '+_('Could not download metadata and/or covers for %d of the books. Click'
- ' "Show details" to see which books.')%len(failed_ids)
- msg = ' ' + _('Finished downloading metadata for %d book(s). '
- 'Proceed with updating the metadata in your library?')%len(id_map)
- q = MessageBox(MessageBox.QUESTION, _('Download complete'),
- msg + fmsg, det_msg=det_msg, show_copy_button=bool(failed_ids),
- parent=gui)
- q.finished.connect(partial(apply_metadata, job, gui, q))
-
- q.vlb = q.bb.addButton(_('View log'), q.bb.ActionRole)
- q.vlb.setIcon(QIcon(I('debug.png')))
- q.vlb.clicked.connect(partial(view_log, job, q))
- q.det_msg_toggle.setVisible(bool(failed_ids | failed_covers))
- q.setModal(False)
- q.show()
-
-# }}}
+ return id_map, failed_ids, failed_covers, all_failed, det_msg
def merge_result(oldmi, newmi):
dummy = Metadata(_('Unknown'))
%s
' % html)
+ l.addWidget(self.tb)
+
+ self.bb = QDialogButtonBox(QDialogButtonBox.Ok)
+ self.bb.accepted.connect(self.accept)
+ self.bb.rejected.connect(self.reject)
+ self.copy_button = self.bb.addButton(_('Copy to clipboard'),
+ self.bb.ActionRole)
+ self.copy_button.setIcon(QIcon(I('edit-copy.png')))
+ self.copy_button.clicked.connect(self.copy_to_clipboard)
+ l.addWidget(self.bb)
+ self.setModal(False)
+ self.resize(QSize(700, 500))
+ self.setWindowTitle(title)
+ self.setWindowIcon(QIcon(I('debug.png')))
+ self.show()
+
+ def copy_to_clipboard(self):
+ txt = self.tb.toPlainText()
+ QApplication.clipboard().setText(txt)
+# }}}
+
+class ProceedNotification(MessageBox):
+
+ proceed = pyqtSignal(object)
+
+ def __init__(self, payload, html_log, log_viewer_title, title, msg, det_msg='', show_copy_button=False, parent=None):
+ MessageBox.__init__(self, MessageBox.QUESTION, title, msg,
+ det_msg=det_msg, show_copy_button=show_copy_button,
+ parent=parent)
+ self.payload = payload
+ self.html_log = html_log
+ self.log_viewer_title = log_viewer_title
+ self.finished.connect(self.do_proceed)
+
+ self.vlb = self.bb.addButton(_('View log'), self.bb.ActionRole)
+ self.vlb.setIcon(QIcon(I('debug.png')))
+ self.vlb.clicked.connect(self.show_log)
+ self.det_msg_toggle.setVisible(bool(det_msg))
+ self.setModal(False)
+
+ def show_log(self):
+ self.log_viewer = ViewLog(self.log_viewer_title, self.html_log,
+ parent=self)
+
+ def do_proceed(self, result):
+ if result == self.Accepted:
+ self.proceed.emit(self.payload)
+ try:
+ self.proceed.disconnect()
+ except:
+ pass
if __name__ == '__main__':
app = QApplication([])
diff --git a/src/calibre/gui2/metadata/bulk_download2.py b/src/calibre/gui2/metadata/bulk_download2.py
index 469f950577..2a307fc902 100644
--- a/src/calibre/gui2/metadata/bulk_download2.py
+++ b/src/calibre/gui2/metadata/bulk_download2.py
@@ -11,14 +11,10 @@ from functools import partial
from itertools import izip
from threading import Event
-from PyQt4.Qt import (QIcon, QDialog, QVBoxLayout, QTextBrowser, QSize,
- QDialogButtonBox, QApplication, QLabel, QGridLayout, QPixmap, Qt)
+from PyQt4.Qt import (QIcon, QDialog,
+ QDialogButtonBox, QLabel, QGridLayout, QPixmap, Qt)
-from calibre.gui2.dialogs.message_box import MessageBox
from calibre.gui2.threaded_jobs import ThreadedJob
-from calibre.utils.icu import lower
-from calibre.ebooks.metadata import authors_to_string
-from calibre.gui2 import question_dialog, error_dialog
from calibre.ebooks.metadata.sources.identify import identify, msprefs
from calibre.ebooks.metadata.sources.covers import download_cover
from calibre.ebooks.metadata.book.base import Metadata
@@ -106,81 +102,7 @@ def start_download(gui, ids, callback):
gui.status_bar.show_message(_('Metadata download started'), 3000)
# }}}
-class ViewLog(QDialog): # {{{
-
- def __init__(self, html, parent=None):
- QDialog.__init__(self, parent)
- self.l = l = QVBoxLayout()
- self.setLayout(l)
-
- self.tb = QTextBrowser(self)
- self.tb.setHtml('%s
' % html)
- l.addWidget(self.tb)
-
- self.bb = QDialogButtonBox(QDialogButtonBox.Ok)
- self.bb.accepted.connect(self.accept)
- self.bb.rejected.connect(self.reject)
- self.copy_button = self.bb.addButton(_('Copy to clipboard'),
- self.bb.ActionRole)
- self.copy_button.setIcon(QIcon(I('edit-copy.png')))
- self.copy_button.clicked.connect(self.copy_to_clipboard)
- l.addWidget(self.bb)
- self.setModal(False)
- self.resize(QSize(700, 500))
- self.setWindowTitle(_('Download log'))
- self.setWindowIcon(QIcon(I('debug.png')))
- self.show()
-
- def copy_to_clipboard(self):
- txt = self.tb.toPlainText()
- QApplication.clipboard().setText(txt)
-
-_vl = None
-def view_log(job, parent):
- global _vl
- _vl = ViewLog(job.html_details, parent)
-
-# }}}
-
-# Apply metadata {{{
-def apply_metadata(job, gui, q, result):
- q.vlb.clicked.disconnect()
- q.finished.disconnect()
- if result != q.Accepted:
- return
- id_map, failed_ids, failed_covers, title_map, all_failed = job.result
- id_map = dict([(k, v) for k, v in id_map.iteritems() if k not in
- failed_ids])
- if not id_map:
- return
-
- modified = set()
- db = gui.current_db
-
- for i, mi in id_map.iteritems():
- lm = db.metadata_last_modified(i, index_is_id=True)
- if lm > mi.last_modified:
- title = db.title(i, index_is_id=True)
- authors = db.authors(i, index_is_id=True)
- if authors:
- authors = [x.replace('|', ',') for x in authors.split(',')]
- title += ' - ' + authors_to_string(authors)
- modified.add(title)
-
- if modified:
- modified = sorted(modified, key=lower)
- if not question_dialog(gui, _('Some books changed'), '