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 threading import Thread
|
||||||
from contextlib import closing
|
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.actions import InterfaceAction
|
||||||
from calibre.gui2 import (error_dialog, Dispatcher, warning_dialog, gprefs,
|
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.gui2.widgets import HistoryLineEdit
|
||||||
from calibre.utils.config import prefs, tweaks
|
from calibre.utils.config import prefs, tweaks
|
||||||
from calibre.utils.date import now
|
from calibre.utils.date import now
|
||||||
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
|
|
||||||
class Worker(Thread): # {{{
|
class Worker(Thread): # {{{
|
||||||
|
|
||||||
@ -47,11 +50,11 @@ class Worker(Thread): # {{{
|
|||||||
|
|
||||||
self.done()
|
self.done()
|
||||||
|
|
||||||
def add_formats(self, id, paths, newdb, replace=True):
|
def add_formats(self, id_, paths, newdb, replace=True):
|
||||||
for path in paths:
|
for path in paths:
|
||||||
fmt = os.path.splitext(path)[-1].replace('.', '').upper()
|
fmt = os.path.splitext(path)[-1].replace('.', '').upper()
|
||||||
with open(path, 'rb') as f:
|
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)
|
notify=False, replace=replace)
|
||||||
|
|
||||||
def doit(self):
|
def doit(self):
|
||||||
@ -174,6 +177,10 @@ class ChooseLibrary(QDialog): # {{{
|
|||||||
return (unicode(self.le.text()), self.delete_after_copy)
|
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):
|
class CopyToLibraryAction(InterfaceAction):
|
||||||
|
|
||||||
name = 'Copy To Library'
|
name = 'Copy To Library'
|
||||||
@ -231,6 +238,11 @@ class CopyToLibraryAction(InterfaceAction):
|
|||||||
_('Cannot copy to current library.'), show=True)
|
_('Cannot copy to current library.'), show=True)
|
||||||
self.copy_to_library(path, delete_after)
|
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):
|
def copy_to_library(self, loc, delete_after=False):
|
||||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||||
if not rows or len(rows) == 0:
|
if not rows or len(rows) == 0:
|
||||||
@ -252,6 +264,39 @@ class CopyToLibraryAction(InterfaceAction):
|
|||||||
self.pd.set_msg(title)
|
self.pd.set_msg(title)
|
||||||
self.pd.set_value(idx)
|
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),
|
self.worker = Worker(ids, db, loc, Dispatcher(progress),
|
||||||
Dispatcher(self.pd.accept), delete_after)
|
Dispatcher(self.pd.accept), delete_after)
|
||||||
self.worker.start()
|
self.worker.start()
|
||||||
@ -295,4 +340,63 @@ class CopyToLibraryAction(InterfaceAction):
|
|||||||
_('You cannot use other libraries while using the environment'
|
_('You cannot use other libraries while using the environment'
|
||||||
' variable CALIBRE_OVERRIDE_DATABASE_PATH.'), show=True)
|
' 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