newdb: Speed up S&R in the bulk metadata edit dialog

This commit is contained in:
Kovid Goyal 2013-08-25 17:30:34 +05:30
parent 1ea50f3d40
commit 138de9b699
2 changed files with 21 additions and 41 deletions

View File

@ -352,11 +352,12 @@ class EditMetadataAction(InterfaceAction):
# Prevent the TagView from updating due to signals from the database # Prevent the TagView from updating due to signals from the database
self.gui.tags_view.blockSignals(True) self.gui.tags_view.blockSignals(True)
changed = False changed = False
refresh_books = set(book_ids)
try: try:
current_tab = 0 current_tab = 0
while True: while True:
dialog = MetadataBulkDialog(self.gui, rows, dialog = MetadataBulkDialog(self.gui, rows,
self.gui.library_view.model(), current_tab) self.gui.library_view.model(), current_tab, refresh_books)
if dialog.changed: if dialog.changed:
changed = True changed = True
if not dialog.do_again: if not dialog.do_again:
@ -365,12 +366,13 @@ class EditMetadataAction(InterfaceAction):
finally: finally:
self.gui.tags_view.blockSignals(False) self.gui.tags_view.blockSignals(False)
if changed: if changed:
refresh_books |= dialog.refresh_books
m = self.gui.library_view.model() m = self.gui.library_view.model()
if gprefs['refresh_book_list_on_bulk_edit']: if gprefs['refresh_book_list_on_bulk_edit']:
m.refresh(reset=False) m.refresh(reset=False)
m.research() m.research()
else: else:
m.refresh_ids(book_ids) m.refresh_ids(refresh_books)
self.gui.tags_view.recount() self.gui.tags_view.recount()
if self.gui.cover_flow: if self.gui.cover_flow:
self.gui.cover_flow.dataChanged() self.gui.cover_flow.dataChanged()

View File

@ -3,8 +3,8 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''Dialog to edit metadata in bulk''' '''Dialog to edit metadata in bulk'''
import re, os, inspect import re, os
from collections import namedtuple from collections import namedtuple, defaultdict
from threading import Thread from threading import Thread
from PyQt4.Qt import Qt, QDialog, QGridLayout, QVBoxLayout, QFont, QLabel, \ from PyQt4.Qt import Qt, QDialog, QGridLayout, QVBoxLayout, QFont, QLabel, \
@ -62,7 +62,7 @@ class MyBlockingBusy(QDialog): # {{{
all_done = pyqtSignal() all_done = pyqtSignal()
def __init__(self, args, ids, db, cc_widgets, s_r_func, do_sr, parent=None, window_title=_('Working')): def __init__(self, args, ids, db, refresh_books, cc_widgets, s_r_func, do_sr, sr_calls, parent=None, window_title=_('Working')):
QDialog.__init__(self, parent) QDialog.__init__(self, parent)
self._layout = l = QVBoxLayout() self._layout = l = QVBoxLayout()
@ -86,6 +86,8 @@ class MyBlockingBusy(QDialog): # {{{
self.db, self.cc_widgets = db, cc_widgets self.db, self.cc_widgets = db, cc_widgets
self.s_r_func = FunctionDispatcher(s_r_func) self.s_r_func = FunctionDispatcher(s_r_func)
self.do_sr = do_sr self.do_sr = do_sr
self.sr_calls = sr_calls
self.refresh_books = refresh_books
def accept(self): def accept(self):
pass pass
@ -276,6 +278,10 @@ class MyBlockingBusy(QDialog): # {{{
if self.do_sr: if self.do_sr:
for book_id in self.ids: for book_id in self.ids:
self.s_r_func(book_id) self.s_r_func(book_id)
if self.sr_calls:
for field, book_id_val_map in self.sr_calls.iteritems():
self.refresh_books.update(self.db.new_api.set_field(field, book_id_val_map))
# }}} # }}}
class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
@ -296,7 +302,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
_('Append to field'), _('Append to field'),
] ]
def __init__(self, window, rows, model, tab): def __init__(self, window, rows, model, tab, refresh_books):
ResizableDialog.__init__(self, window) ResizableDialog.__init__(self, window)
Ui_MetadataBulkDialog.__init__(self) Ui_MetadataBulkDialog.__init__(self)
self.model = model self.model = model
@ -309,6 +315,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
len(rows)) len(rows))
self.write_series = False self.write_series = False
self.changed = False self.changed = False
self.refresh_books = refresh_books
all_tags = self.db.all_tags() all_tags = self.db.all_tags()
self.tags.update_items_cache(all_tags) self.tags.update_items_cache(all_tags)
@ -790,7 +797,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
self.s_r_set_colors() self.s_r_set_colors()
break break
def do_search_replace(self, id): def do_search_replace(self, book_id):
source = self.s_r_sf_itemdata(None) source = self.s_r_sf_itemdata(None)
if not source or not self.s_r_obj: if not source or not self.s_r_obj:
return return
@ -798,7 +805,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
if not dest: if not dest:
dest = source dest = source
dfm = self.db.field_metadata[dest] dfm = self.db.field_metadata[dest]
mi = self.db.get_metadata(id, index_is_id=True) mi = self.db.new_api.get_proxy_metadata(book_id)
val = self.s_r_do_regexp(mi) val = self.s_r_do_regexp(mi)
val = self.s_r_do_destination(mi, val) val = self.s_r_do_destination(mi, val)
if dfm['is_multiple']: if dfm['is_multiple']:
@ -823,37 +830,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
if dest == 'title' and len(val) == 0: if dest == 'title' and len(val) == 0:
val = _('Unknown') val = _('Unknown')
if dfm['is_custom']: self.set_field_calls[dest][book_id] = val
extra = self.db.get_custom_extra(id, label=dfm['label'], index_is_id=True)
books_to_refresh = self.db.set_custom(id, val, label=dfm['label'],
extra=extra, commit=False,
allow_case_change=True)
elif dest.startswith('#') and dest.endswith('_index'):
label = self.db.field_metadata[dest[:-6]]['label']
series = self.db.get_custom(id, label=label, index_is_id=True)
books_to_refresh = self.db.set_custom(id, series, label=label,
extra=val, commit=False,
allow_case_change=True)
else:
if dest == 'comments':
setter = self.db.set_comment
elif dest == 'sort':
setter = self.db.set_title_sort
else:
setter = getattr(self.db, 'set_'+dest)
args = inspect.getargspec(setter)
if args and 'allow_case_change' in args.args:
books_to_refresh = setter(id, val, notify=False, commit=False,
allow_case_change=True)
else:
setter(id, val, notify=False, commit=False)
books_to_refresh = set([])
if books_to_refresh:
# Must commit here because we are telling the gui that the data is
# permanent. Make sure it really is.
self.db.commit()
self.model.refresh_ids(list(books_to_refresh))
# }}} # }}}
def create_custom_column_editors(self): def create_custom_column_editors(self):
@ -993,9 +970,10 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
source = self.s_r_sf_itemdata(None) source = self.s_r_sf_itemdata(None)
do_sr = source and self.s_r_obj do_sr = source and self.s_r_obj
bb = MyBlockingBusy(args, self.ids, self.db, self.set_field_calls = defaultdict(dict)
bb = MyBlockingBusy(args, self.ids, self.db, self.refresh_books,
getattr(self, 'custom_column_widgets', []), getattr(self, 'custom_column_widgets', []),
self.do_search_replace, do_sr, parent=self) self.do_search_replace, do_sr, self.set_field_calls, parent=self)
# The metadata backup thread causes database commits # The metadata backup thread causes database commits
# which can slow down bulk editing of large numbers of books # which can slow down bulk editing of large numbers of books