Merge from trunk

This commit is contained in:
Charles Haley 2010-08-18 20:09:26 +01:00
commit dc5f3871ed
3 changed files with 85 additions and 76 deletions

View File

@ -3,8 +3,9 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''Dialog to edit metadata in bulk'''
from PyQt4.Qt import SIGNAL, QObject, QDialog, QGridLayout, \
QThread, Qt
from threading import Thread
from PyQt4.Qt import QDialog, QGridLayout
from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
from calibre.gui2.dialogs.tag_editor import TagEditor
@ -12,18 +13,73 @@ from calibre.ebooks.metadata import string_to_authors, \
authors_to_string
from calibre.gui2.custom_column_widgets import populate_metadata_page
from calibre.gui2.dialogs.progress import BlockingBusy
from calibre.gui2 import error_dialog
from calibre.gui2 import error_dialog, Dispatcher
class Worker(QThread):
class Worker(Thread):
def __init__(self, func, parent=None):
QThread.__init__(self, parent)
self.func = func
def __init__(self, args, db, ids, callback):
Thread.__init__(self)
self.args = args
self.db = db
self.ids = ids
self.error = None
self.callback = callback
def doit(self):
remove, add, au, aus, do_aus, rating, pub, do_series, \
do_autonumber, do_remove_format, remove_format, do_swap_ta, \
do_remove_conv, do_auto_author, series = self.args
for id in self.ids:
if do_swap_ta:
title = self.db.title(id, index_is_id=True)
aum = self.db.authors(id, index_is_id=True)
if aum:
aum = [a.strip().replace('|', ',') for a in aum.split(',')]
new_title = authors_to_string(aum)
self.db.set_title(id, new_title, notify=False)
if title:
new_authors = string_to_authors(title)
self.db.set_authors(id, new_authors, notify=False)
if au:
self.db.set_authors(id, string_to_authors(au), notify=False)
if do_auto_author:
x = self.db.author_sort_from_book(id, index_is_id=True)
if x:
self.db.set_author_sort(id, x, notify=False)
if aus and do_aus:
self.db.set_author_sort(id, aus, notify=False)
if rating != -1:
self.db.set_rating(id, 2*rating, notify=False)
if pub:
self.db.set_publisher(id, pub, notify=False)
if do_series:
next = self.db.get_next_series_num_for(series)
self.db.set_series(id, series, notify=False)
num = next if do_autonumber and series else 1.0
self.db.set_series_index(id, num, notify=False)
if do_remove_format:
self.db.remove_format(id, remove_format, index_is_id=True, notify=False)
if do_remove_conv:
self.db.delete_conversion_options(id, 'PIPE')
for w in getattr(self, 'custom_column_widgets', []):
w.commit(self.ids)
self.db.bulk_modify_tags(self.ids, add=add, remove=remove,
notify=False)
self.db.clean()
def run(self):
try:
self.func()
self.doit()
except Exception, err:
import traceback
try:
@ -32,6 +88,9 @@ class Worker(QThread):
err = repr(err)
self.error = (err, traceback.format_exc())
self.callback()
class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
def __init__(self, window, rows, db):
@ -57,9 +116,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
self.remove_format.setCurrentIndex(-1)
QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.series_changed)
QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.series_changed)
QObject.connect(self.tag_editor_button, SIGNAL('clicked()'), self.tag_editor)
self.series.currentIndexChanged[int].connect(self.series_changed)
self.series.editTextChanged.connect(self.series_changed)
self.tag_editor_button.clicked.connect(self.tag_editor)
if len(db.custom_column_label_map) == 0:
self.central_widget.tabBar().setVisible(False)
else:
@ -113,7 +172,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
self.publisher.addItem(name)
self.publisher.setEditText('')
def tag_editor(self):
def tag_editor(self, *args):
d = TagEditor(self, self.db, None)
d.exec_()
if d.result() == QDialog.Accepted:
@ -126,6 +185,12 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
if len(self.ids) < 1:
return QDialog.accept(self)
self.changed = bool(self.ids)
# Cache values from GUI so that Qt widgets are not used in
# non GUI thread
for w in getattr(self, 'custom_column_widgets', []):
w.gui_val
remove = unicode(self.remove_tags.text()).strip().split(',')
add = unicode(self.tags.text()).strip().split(',')
au = unicode(self.authors.text())
@ -141,72 +206,16 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
do_swap_ta = self.swap_title_and_author.isChecked()
do_remove_conv = self.remove_conversion_settings.isChecked()
do_auto_author = self.auto_author_sort.isChecked()
self.changed = bool(self.ids)
# Cache values from GUI so that Qt widgets are not used in
# non GUI thread
for w in getattr(self, 'custom_column_widgets', []):
w.gui_val
def doit():
# author and title changes cause file system changes as well as
# database changes. Do these as individual transactions, so that
# exceptions do the smallest amount of damage
for id in self.ids:
if do_swap_ta:
title = self.db.title(id, index_is_id=True)
aum = self.db.authors(id, index_is_id=True)
if aum:
aum = [a.strip().replace('|', ',') for a in aum.split(',')]
new_title = authors_to_string(aum)
self.db.set_title(id, new_title, notify=False)
if title:
new_authors = string_to_authors(title)
self.db.set_authors(id, new_authors, notify=False)
if au:
self.db.set_authors(id, string_to_authors(au), notify=False)
# all of the following are database-only operations, so do them
# as a single transaction
for id in self.ids:
if do_auto_author:
x = self.db.author_sort_from_book(id, index_is_id=True)
if x:
self.db.set_author_sort(id, x, notify=False, commit=False)
if aus and do_aus:
self.db.set_author_sort(id, aus, notify=False, commit=False)
if rating != -1:
self.db.set_rating(id, 2*rating, notify=False, commit=False)
if pub:
self.db.set_publisher(id, pub, notify=False, commit=False)
if do_series:
next = self.db.get_next_series_num_for(series)
self.db.set_series(id, series, notify=False, commit=False)
num = next if do_autonumber and series else 1.0
self.db.set_series_index(id, num, notify=False, commit=False)
if do_remove_format:
self.db.remove_format(id, remove_format, index_is_id=True, notify=False, commit=False)
if do_remove_conv:
self.db.delete_conversion_options(id, 'PIPE')
self.db.conn.commit()
for w in getattr(self, 'custom_column_widgets', []):
w.commit(self.ids)
self.db.bulk_modify_tags(self.ids, add=add, remove=remove,
notify=False)
self.db.clean()
self.worker = Worker(doit, self)
self.worker.start()
args = (remove, add, au, aus, do_aus, rating, pub, do_series,
do_autonumber, do_remove_format, remove_format, do_swap_ta,
do_remove_conv, do_auto_author, series)
bb = BlockingBusy(_('Applying changes to %d books. This may take a while.')
%len(self.ids), parent=self)
self.worker.finished.connect(bb.accept, type=Qt.QueuedConnection)
self.worker = Worker(args, self.db, self.ids, Dispatcher(bb.accept,
parent=bb))
self.worker.start()
bb.exec_()
if self.worker.error is not None:

View File

@ -377,7 +377,7 @@ class CustomColumns(object):
if add:
self.conn.execute(
'''
INSERT INTO {0}(book, value) SELECT {1}.id, {2}.id FROM {1}, {2}
INSERT OR REPLACE INTO {0}(book, value) SELECT {1}.id, {2}.id FROM {1}, {2}
'''.format(link_table, temp_tables[0], temp_tables[1])
)
# get rid of the temp tables

View File

@ -1438,7 +1438,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if add:
self.conn.execute(
'''
INSERT INTO books_tags_link(book, tag) SELECT {0}.id, {1}.id FROM
INSERT OR REPLACE INTO books_tags_link(book, tag) SELECT {0}.id, {1}.id FROM
{0}, {1}
'''.format(tables[0], tables[1])
)