Start work on porting the bulk metadata dialog to the new API

This commit is contained in:
Kovid Goyal 2013-07-21 15:48:42 +05:30
parent a5e32b4ad4
commit b2733f6052
2 changed files with 115 additions and 1 deletions

View File

@ -333,6 +333,12 @@ class Cache(object):
except (KeyError, IndexError): except (KeyError, IndexError):
return default_value return default_value
@read_api
def all_field_for(self, field, book_ids, default_value=None):
' Same as field_for, except that it operates on multiple books at once '
field_obj = self.fields[field]
return {book_id:self._fast_field_for(field_obj, book_id, default_value=default_value) for book_id in book_ids}
@read_api @read_api
def composite_for(self, name, book_id, mi=None, default_value=''): def composite_for(self, name, book_id, mi=None, default_value=''):
try: try:

View File

@ -5,6 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import re, os, inspect import re, os, inspect
from collections import namedtuple from collections import namedtuple
from threading import Thread
from PyQt4.Qt import Qt, QDialog, QGridLayout, QVBoxLayout, QFont, QLabel, \ from PyQt4.Qt import Qt, QDialog, QGridLayout, QVBoxLayout, QFont, QLabel, \
pyqtSignal, QDialogButtonBox, QInputDialog, QLineEdit, \ pyqtSignal, QDialogButtonBox, QInputDialog, QLineEdit, \
@ -58,6 +59,106 @@ Settings = namedtuple('Settings', 'remove_all remove add au aus do_aus rating pu
'remove_format do_swap_ta do_remove_conv do_auto_author series do_series_restart series_start_value ' 'remove_format do_swap_ta do_remove_conv do_auto_author series do_series_restart series_start_value '
'do_title_case cover_action clear_series pubdate adddate do_title_sort languages clear_languages restore_original') 'do_title_case cover_action clear_series pubdate adddate do_title_sort languages clear_languages restore_original')
class MyBlockingBusyNew(QDialog):
all_done = pyqtSignal()
def __init__(self, args, ids, db, cc_widgets, s_r_func,
parent=None, window_title=_('Working')):
QDialog.__init__(self, parent)
self._layout = l = QVBoxLayout()
self.setLayout(l)
self.msg = QLabel(_('Processing %d books, please wait...') % len(ids))
self.font = QFont()
self.font.setPointSize(self.font.pointSize() + 8)
self.msg.setFont(self.font)
self.pi = ProgressIndicator(self)
self.pi.setDisplaySize(100)
self._layout.addWidget(self.pi, 0, Qt.AlignHCenter)
self._layout.addSpacing(15)
self._layout.addWidget(self.msg, 0, Qt.AlignHCenter)
self.setWindowTitle(window_title + '...')
self.setMinimumWidth(200)
self.resize(self.sizeHint())
self.error = None
self.all_done.connect(self.on_all_done, type=Qt.QueuedConnection)
self.args, self.ids, self.s_r_func = args, ids, s_r_func
self.db, self.cc_widgets = db, cc_widgets
def accept(self):
pass
def reject(self):
pass
def on_all_done(self):
QDialog.accept(self)
def exec_(self):
self.thread = Thread(target=self.do_it)
self.thread.start()
return QDialog.exec_(self)
def do_it(self):
try:
self.do_all()
except Exception as err:
import traceback
try:
err = unicode(err)
except:
err = repr(err)
self.error = (err, traceback.format_exc())
self.all_done.emit()
def do_all(self):
cache = self.db.new_api
args = self.args
# Title and authors
if args.do_swap_ta:
title_map = cache.all_field_for('title', self.ids)
authors_map = cache.all_field_for('authors', self.ids)
def new_title(authors):
ans = authors_to_string(authors)
return titlecase(ans) if args.do_title_case else ans
new_title_map = {bid:new_title(authors) for bid, authors in authors_map.iteritems()}
new_authors_map = {bid:string_to_authors(title) for bid, title in title_map.iteritems()}
cache.set_field('authors', new_authors_map)
cache.set_field('title', new_title_map)
if args.do_title_case and not args.do_swap_ta:
title_map = cache.all_field_for('title', self.ids)
cache.set_field('title', {bid:titlecase(title) for bid, title in title_map.iteritems()})
if args.do_title_sort:
lang_map = cache.all_field_for('languages', self.ids)
title_map = cache.all_field_for('title', self.ids)
def get_sort(book_id):
if args.languages:
lang = args.languages[0]
else:
try:
lang = lang_map[book_id][0]
except (KeyError, IndexError, TypeError, AttributeError):
lang = 'eng'
return title_sort(title_map[book_id], lang=lang)
cache.set_field('sort', {bid:get_sort(bid) for bid in self.ids})
if args.au:
authors = string_to_authors(args.au)
cache.set_field('authors', {bid:authors for bid in self.ids})
if args.do_auto_author:
aus_map = cache.author_sort_strings_for_books(self.ids)
cache.set_field('author_sort', {book_id:' & '.join(aus_map[book_id]) for book_id in aus_map})
if args.aus and args.do_aus:
cache.set_field('author_sort', {bid:args.aus for bid in self.ids})
class MyBlockingBusy(QDialog): # {{{ class MyBlockingBusy(QDialog): # {{{
do_one_signal = pyqtSignal() do_one_signal = pyqtSignal()
@ -1010,7 +1111,12 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
pubdate, adddate, do_title_sort, languages, clear_languages, pubdate, adddate, do_title_sort, languages, clear_languages,
restore_original) restore_original)
bb = MyBlockingBusy(_('Applying changes to %d books.\nPhase {0} {1}%%.') if hasattr(self.db, 'new_api'):
bb = MyBlockingBusyNew(args, self.ids, self.db,
getattr(self, 'custom_column_widgets', []),
self.do_search_replace, parent=self)
else:
bb = MyBlockingBusy(_('Applying changes to %d books.\nPhase {0} {1}%%.')
%len(self.ids), args, self.db, self.ids, %len(self.ids), args, self.db, self.ids,
getattr(self, 'custom_column_widgets', []), getattr(self, 'custom_column_widgets', []),
self.do_search_replace, parent=self) self.do_search_replace, parent=self)
@ -1023,6 +1129,8 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
finally: finally:
self.model.start_metadata_backup() self.model.start_metadata_backup()
bb.thread = bb.db = bb.cc_widgets = None
if bb.error is not None: if bb.error is not None:
return error_dialog(self, _('Failed'), return error_dialog(self, _('Failed'),
bb.error[0], det_msg=bb.error[1], bb.error[0], det_msg=bb.error[1],