mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
When copying books from library A to library B, check that B contains the necessary custom columns. If not, tell the user and allow them to create any non-conflicting columns. Inform them about conflicting columns.
This commit is contained in:
parent
3d12ae2e9e
commit
7d77e8fe98
@ -10,7 +10,8 @@ from functools import partial
|
||||
from threading import Thread
|
||||
from contextlib import closing
|
||||
|
||||
from PyQt4.Qt import (QToolButton, QDialog, QGridLayout, QIcon, QLabel, QDialogButtonBox)
|
||||
from PyQt4.Qt import (QToolButton, QDialog, QGridLayout, QIcon, QLabel, QDialogButtonBox,
|
||||
QFormLayout, QCheckBox)
|
||||
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
from calibre.gui2 import (error_dialog, Dispatcher, warning_dialog, gprefs,
|
||||
@ -19,6 +20,8 @@ from calibre.gui2.dialogs.progress import ProgressDialog
|
||||
from calibre.gui2.widgets import HistoryLineEdit
|
||||
from calibre.utils.config import prefs, tweaks
|
||||
from calibre.utils.date import now
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
|
||||
class Worker(Thread): # {{{
|
||||
|
||||
@ -47,11 +50,11 @@ class Worker(Thread): # {{{
|
||||
|
||||
self.done()
|
||||
|
||||
def add_formats(self, id, paths, newdb, replace=True):
|
||||
def add_formats(self, id_, paths, newdb, replace=True):
|
||||
for path in paths:
|
||||
fmt = os.path.splitext(path)[-1].replace('.', '').upper()
|
||||
with open(path, 'rb') as f:
|
||||
newdb.add_format(id, fmt, f, index_is_id=True,
|
||||
newdb.add_format(id_, fmt, f, index_is_id=True,
|
||||
notify=False, replace=replace)
|
||||
|
||||
def doit(self):
|
||||
@ -174,6 +177,10 @@ class ChooseLibrary(QDialog): # {{{
|
||||
return (unicode(self.le.text()), self.delete_after_copy)
|
||||
# }}}
|
||||
|
||||
# Static session-long set of pairs of libraries that have had their custom columns
|
||||
# checked for compatibility
|
||||
libraries_with_checked_columns = {}
|
||||
|
||||
class CopyToLibraryAction(InterfaceAction):
|
||||
|
||||
name = 'Copy To Library'
|
||||
@ -231,6 +238,11 @@ class CopyToLibraryAction(InterfaceAction):
|
||||
_('Cannot copy to current library.'), show=True)
|
||||
self.copy_to_library(path, delete_after)
|
||||
|
||||
def _column_is_compatible(self, source_metadata, dest_metadata):
|
||||
return (source_metadata['datatype'] == dest_metadata['datatype'] and
|
||||
(source_metadata['datatype'] != 'text' or
|
||||
source_metadata['is_multiple'] == dest_metadata['is_multiple']))
|
||||
|
||||
def copy_to_library(self, loc, delete_after=False):
|
||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) == 0:
|
||||
@ -252,6 +264,39 @@ class CopyToLibraryAction(InterfaceAction):
|
||||
self.pd.set_msg(title)
|
||||
self.pd.set_value(idx)
|
||||
|
||||
# Open the new db so we can check the custom columns.
|
||||
|
||||
global libraries_with_checked_columns
|
||||
if db.library_id not in libraries_with_checked_columns:
|
||||
libraries_with_checked_columns[db.library_id] = set()
|
||||
|
||||
from calibre.db.legacy import LibraryDatabase
|
||||
newdb = LibraryDatabase(loc, is_second_db=True)
|
||||
|
||||
continue_processing = True;
|
||||
with closing(newdb):
|
||||
if newdb.library_id not in libraries_with_checked_columns[db.library_id]:
|
||||
|
||||
newdb_meta = newdb.field_metadata.custom_field_metadata()
|
||||
incompatible_columns = []
|
||||
missing_columns = []
|
||||
for k, m in db.field_metadata.custom_iteritems():
|
||||
if k not in newdb_meta:
|
||||
missing_columns.append(k)
|
||||
elif not self._column_is_compatible(m, newdb_meta[k]):
|
||||
incompatible_columns.append(k)
|
||||
|
||||
if missing_columns or incompatible_columns:
|
||||
continue_processing = self.custom_column_dialog(db, newdb,
|
||||
missing_columns, incompatible_columns)
|
||||
if continue_processing:
|
||||
libraries_with_checked_columns[db.library_id].add(newdb.library_id)
|
||||
|
||||
newdb.break_cycles()
|
||||
del newdb
|
||||
if not continue_processing:
|
||||
return;
|
||||
|
||||
self.worker = Worker(ids, db, loc, Dispatcher(progress),
|
||||
Dispatcher(self.pd.accept), delete_after)
|
||||
self.worker.start()
|
||||
@ -295,4 +340,63 @@ class CopyToLibraryAction(InterfaceAction):
|
||||
_('You cannot use other libraries while using the environment'
|
||||
' variable CALIBRE_OVERRIDE_DATABASE_PATH.'), show=True)
|
||||
|
||||
def custom_column_dialog(self, db, newdb, missing_cols, incompatible_cols):
|
||||
source_metadata = db.field_metadata.custom_field_metadata(include_composites=True)
|
||||
|
||||
d = QDialog(self.gui)
|
||||
d.setWindowTitle(_('Create link'))
|
||||
l = QFormLayout()
|
||||
d.setLayout(l)
|
||||
d.setMinimumWidth(600)
|
||||
d.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
|
||||
|
||||
d.la = la = QLabel(_(
|
||||
'The custom columns in the source library are different from the '
|
||||
'custom columns in the destination library. Incompatible columns '
|
||||
'are columns with the same lookup key but different column '
|
||||
'types. These cannot be copied. Missing columns are columns '
|
||||
'in the source library but not in the destination library. '
|
||||
'If you check the "Create" box, these columns will be added '
|
||||
'to the destination and their values copied with the books.'))
|
||||
la.setWordWrap(True)
|
||||
la.setStyleSheet('QLabel { margin-bottom: 1.5ex }')
|
||||
l.setWidget(0, l.SpanningRole, la)
|
||||
if incompatible_cols:
|
||||
l.addRow(_('Incompatible custom columns:'),
|
||||
QLabel(', '.join(sorted(incompatible_cols, key=sort_key))))
|
||||
|
||||
incompatible_cols_widgets = []
|
||||
if missing_cols:
|
||||
l.addRow(QLabel(_('Missing custom columns')), QLabel(''))
|
||||
for k in missing_cols:
|
||||
widgets = (k, QCheckBox(_('Add column to new library')))
|
||||
l.addRow(QLabel(k), widgets[1])
|
||||
incompatible_cols_widgets.append(widgets)
|
||||
|
||||
l.addRow(d.bb)
|
||||
d.bb.accepted.connect(d.accept)
|
||||
d.bb.rejected.connect(d.reject)
|
||||
d.resize(d.sizeHint())
|
||||
if d.exec_() == d.Accepted:
|
||||
count = 0
|
||||
for k,cb in incompatible_cols_widgets:
|
||||
if cb.isChecked():
|
||||
count += 1
|
||||
if count:
|
||||
pd = ProgressDialog(_('Creating custom columns'), min=0, max=count,
|
||||
parent=self.gui, cancelable=False)
|
||||
pd.show()
|
||||
done_count = 0
|
||||
for k,cb in incompatible_cols_widgets:
|
||||
if cb.isChecked():
|
||||
pd.set_value(done_count)
|
||||
pd.set_msg(_('Creating column {0}').format(k))
|
||||
done_count += 1
|
||||
col_meta = source_metadata[k]
|
||||
newdb.create_custom_column(
|
||||
col_meta['label'], col_meta['name'], col_meta['datatype'],
|
||||
len(col_meta['is_multiple']) > 0,
|
||||
col_meta['is_editable'], col_meta['display'])
|
||||
pd.done(0)
|
||||
return True
|
||||
return False
|
Loading…
x
Reference in New Issue
Block a user