mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
dc5f3871ed
@ -3,8 +3,9 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
|
|
||||||
'''Dialog to edit metadata in bulk'''
|
'''Dialog to edit metadata in bulk'''
|
||||||
|
|
||||||
from PyQt4.Qt import SIGNAL, QObject, QDialog, QGridLayout, \
|
from threading import Thread
|
||||||
QThread, Qt
|
|
||||||
|
from PyQt4.Qt import QDialog, QGridLayout
|
||||||
|
|
||||||
from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
|
from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
|
||||||
from calibre.gui2.dialogs.tag_editor import TagEditor
|
from calibre.gui2.dialogs.tag_editor import TagEditor
|
||||||
@ -12,18 +13,73 @@ from calibre.ebooks.metadata import string_to_authors, \
|
|||||||
authors_to_string
|
authors_to_string
|
||||||
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
||||||
from calibre.gui2.dialogs.progress import BlockingBusy
|
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):
|
def __init__(self, args, db, ids, callback):
|
||||||
QThread.__init__(self, parent)
|
Thread.__init__(self)
|
||||||
self.func = func
|
self.args = args
|
||||||
|
self.db = db
|
||||||
|
self.ids = ids
|
||||||
self.error = None
|
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):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
self.func()
|
self.doit()
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
import traceback
|
import traceback
|
||||||
try:
|
try:
|
||||||
@ -32,6 +88,9 @@ class Worker(QThread):
|
|||||||
err = repr(err)
|
err = repr(err)
|
||||||
self.error = (err, traceback.format_exc())
|
self.error = (err, traceback.format_exc())
|
||||||
|
|
||||||
|
self.callback()
|
||||||
|
|
||||||
|
|
||||||
class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||||
|
|
||||||
def __init__(self, window, rows, db):
|
def __init__(self, window, rows, db):
|
||||||
@ -57,9 +116,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
|
|
||||||
self.remove_format.setCurrentIndex(-1)
|
self.remove_format.setCurrentIndex(-1)
|
||||||
|
|
||||||
QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.series_changed)
|
self.series.currentIndexChanged[int].connect(self.series_changed)
|
||||||
QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.series_changed)
|
self.series.editTextChanged.connect(self.series_changed)
|
||||||
QObject.connect(self.tag_editor_button, SIGNAL('clicked()'), self.tag_editor)
|
self.tag_editor_button.clicked.connect(self.tag_editor)
|
||||||
if len(db.custom_column_label_map) == 0:
|
if len(db.custom_column_label_map) == 0:
|
||||||
self.central_widget.tabBar().setVisible(False)
|
self.central_widget.tabBar().setVisible(False)
|
||||||
else:
|
else:
|
||||||
@ -113,7 +172,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
self.publisher.addItem(name)
|
self.publisher.addItem(name)
|
||||||
self.publisher.setEditText('')
|
self.publisher.setEditText('')
|
||||||
|
|
||||||
def tag_editor(self):
|
def tag_editor(self, *args):
|
||||||
d = TagEditor(self, self.db, None)
|
d = TagEditor(self, self.db, None)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
if d.result() == QDialog.Accepted:
|
if d.result() == QDialog.Accepted:
|
||||||
@ -126,6 +185,12 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
if len(self.ids) < 1:
|
if len(self.ids) < 1:
|
||||||
return QDialog.accept(self)
|
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(',')
|
remove = unicode(self.remove_tags.text()).strip().split(',')
|
||||||
add = unicode(self.tags.text()).strip().split(',')
|
add = unicode(self.tags.text()).strip().split(',')
|
||||||
au = unicode(self.authors.text())
|
au = unicode(self.authors.text())
|
||||||
@ -141,72 +206,16 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
do_swap_ta = self.swap_title_and_author.isChecked()
|
do_swap_ta = self.swap_title_and_author.isChecked()
|
||||||
do_remove_conv = self.remove_conversion_settings.isChecked()
|
do_remove_conv = self.remove_conversion_settings.isChecked()
|
||||||
do_auto_author = self.auto_author_sort.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():
|
args = (remove, add, au, aus, do_aus, rating, pub, do_series,
|
||||||
# author and title changes cause file system changes as well as
|
do_autonumber, do_remove_format, remove_format, do_swap_ta,
|
||||||
# database changes. Do these as individual transactions, so that
|
do_remove_conv, do_auto_author, series)
|
||||||
# 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()
|
|
||||||
|
|
||||||
bb = BlockingBusy(_('Applying changes to %d books. This may take a while.')
|
bb = BlockingBusy(_('Applying changes to %d books. This may take a while.')
|
||||||
%len(self.ids), parent=self)
|
%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_()
|
bb.exec_()
|
||||||
|
|
||||||
if self.worker.error is not None:
|
if self.worker.error is not None:
|
||||||
|
@ -377,7 +377,7 @@ class CustomColumns(object):
|
|||||||
if add:
|
if add:
|
||||||
self.conn.execute(
|
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])
|
'''.format(link_table, temp_tables[0], temp_tables[1])
|
||||||
)
|
)
|
||||||
# get rid of the temp tables
|
# get rid of the temp tables
|
||||||
|
@ -1438,7 +1438,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
if add:
|
if add:
|
||||||
self.conn.execute(
|
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}
|
{0}, {1}
|
||||||
'''.format(tables[0], tables[1])
|
'''.format(tables[0], tables[1])
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user