mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Series custom columns seem to work
This commit is contained in:
parent
8d316781f5
commit
5544a5d222
@ -5,7 +5,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys
|
||||
import re, sys
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \
|
||||
@ -162,7 +162,6 @@ class DateTime(Base):
|
||||
val = qt_to_dt(val)
|
||||
return val
|
||||
|
||||
|
||||
class Comments(Base):
|
||||
|
||||
def setup_ui(self, parent):
|
||||
@ -199,11 +198,7 @@ class Text(Base):
|
||||
w = EnComboBox(parent)
|
||||
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
|
||||
w.setMinimumContentsLength(25)
|
||||
|
||||
|
||||
|
||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||
w]
|
||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), w]
|
||||
|
||||
def initialize(self, book_id):
|
||||
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
||||
@ -222,7 +217,6 @@ class Text(Base):
|
||||
if idx is not None:
|
||||
self.widgets[1].setCurrentIndex(idx)
|
||||
|
||||
|
||||
def setter(self, val):
|
||||
if self.col_metadata['is_multiple']:
|
||||
if not val:
|
||||
@ -241,6 +235,58 @@ class Text(Base):
|
||||
val = None
|
||||
return val
|
||||
|
||||
class Series(Base):
|
||||
|
||||
def setup_ui(self, parent):
|
||||
values = self.all_values = list(self.db.all_custom(num=self.col_id))
|
||||
values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower()))
|
||||
w = EnComboBox(parent)
|
||||
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
|
||||
w.setMinimumContentsLength(25)
|
||||
self.name_widget = w
|
||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), w]
|
||||
|
||||
self.widgets.append(QLabel('&'+self.col_metadata['name']+_(' index:'), parent))
|
||||
w = QDoubleSpinBox(parent)
|
||||
w.setRange(-100., float(sys.maxint))
|
||||
w.setDecimals(2)
|
||||
w.setSpecialValueText(_('Undefined'))
|
||||
w.setSingleStep(1)
|
||||
self.idx_widget=w
|
||||
self.widgets.append(w)
|
||||
|
||||
def initialize(self, book_id):
|
||||
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
||||
s_index = self.db.get_custom_extra(book_id, num=self.col_id, index_is_id=True)
|
||||
if s_index is None:
|
||||
s_index = 0.0
|
||||
self.idx_widget.setValue(s_index)
|
||||
self.initial_index = s_index
|
||||
self.initial_val = val
|
||||
val = self.normalize_db_val(val)
|
||||
idx = None
|
||||
for i, c in enumerate(self.all_values):
|
||||
if c == val:
|
||||
idx = i
|
||||
self.name_widget.addItem(c)
|
||||
self.name_widget.setEditText('')
|
||||
if idx is not None:
|
||||
self.widgets[1].setCurrentIndex(idx)
|
||||
|
||||
def commit(self, book_id, notify=False):
|
||||
val = unicode(self.name_widget.currentText()).strip()
|
||||
val = self.normalize_ui_val(val)
|
||||
s_index = self.idx_widget.value()
|
||||
if val != self.initial_val or s_index != self.initial_index:
|
||||
if s_index == 0.0:
|
||||
if tweaks['series_index_auto_increment'] == 'next':
|
||||
s_index = self.db.get_next_cc_series_num_for(val,
|
||||
num=self.col_id)
|
||||
else:
|
||||
s_index = None
|
||||
self.db.set_custom(book_id, val, extra=s_index,
|
||||
num=self.col_id, notify=notify)
|
||||
|
||||
widgets = {
|
||||
'bool' : Bool,
|
||||
'rating' : Rating,
|
||||
@ -249,6 +295,7 @@ widgets = {
|
||||
'datetime': DateTime,
|
||||
'text' : Text,
|
||||
'comments': Comments,
|
||||
'series': Series,
|
||||
}
|
||||
|
||||
def field_sort(y, z, x=None):
|
||||
@ -257,35 +304,63 @@ def field_sort(y, z, x=None):
|
||||
n2 = 'zzzzz' if m2['datatype'] == 'comments' else m2['name']
|
||||
return cmp(n1.lower(), n2.lower())
|
||||
|
||||
def populate_single_metadata_page(left, right, db, book_id, parent=None):
|
||||
def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, parent=None):
|
||||
def widget_factory(type, col):
|
||||
if bulk:
|
||||
w = bulk_widgets[type](db, col, parent)
|
||||
else:
|
||||
w = widgets[type](db, col, parent)
|
||||
w.initialize(book_id)
|
||||
return w
|
||||
x = db.custom_column_num_map
|
||||
cols = list(x)
|
||||
cols.sort(cmp=partial(field_sort, x=x))
|
||||
count_non_comment = len([c for c in cols if x[c]['datatype'] != 'comments'])
|
||||
|
||||
layout.setColumnStretch(1, 10)
|
||||
if two_column:
|
||||
turnover_point = (count_non_comment+1)/2
|
||||
layout.setColumnStretch(3, 10)
|
||||
else:
|
||||
# Avoid problems with multi-line widgets
|
||||
turnover_point = count_non_comment + 1000
|
||||
ans = []
|
||||
for i, col in enumerate(cols):
|
||||
w = widgets[x[col]['datatype']](db, col, parent)
|
||||
column = row = 0
|
||||
for col in cols:
|
||||
dt = x[col]['datatype']
|
||||
if dt == 'comments':
|
||||
continue
|
||||
w = widget_factory(dt, col)
|
||||
ans.append(w)
|
||||
w.initialize(book_id)
|
||||
layout = left if i%2 == 0 else right
|
||||
row = layout.rowCount()
|
||||
if len(w.widgets) == 1:
|
||||
layout.addWidget(w.widgets[0], row, 0, 1, -1)
|
||||
else:
|
||||
w.widgets[0].setBuddy(w.widgets[1])
|
||||
for c, widget in enumerate(w.widgets):
|
||||
layout.addWidget(widget, row, c)
|
||||
for c in range(0, len(w.widgets), 2):
|
||||
w.widgets[c].setBuddy(w.widgets[c+1])
|
||||
layout.addWidget(w.widgets[c], row, column)
|
||||
layout.addWidget(w.widgets[c+1], row, column+1)
|
||||
row += 1
|
||||
if row >= turnover_point:
|
||||
column += 2
|
||||
turnover_point = count_non_comment + 1000
|
||||
row = 0
|
||||
if not bulk: # Add the comments fields
|
||||
column = 0
|
||||
for col in cols:
|
||||
dt = x[col]['datatype']
|
||||
if dt != 'comments':
|
||||
continue
|
||||
w = widget_factory(dt, col)
|
||||
ans.append(w)
|
||||
layout.addWidget(w.widgets[0], row, column, 1, 2)
|
||||
if two_column and column == 0:
|
||||
column = 2
|
||||
continue
|
||||
column = 0
|
||||
row += 1
|
||||
items = []
|
||||
if len(ans) > 0:
|
||||
items.append(QSpacerItem(10, 10, QSizePolicy.Minimum,
|
||||
QSizePolicy.Expanding))
|
||||
left.addItem(items[-1], left.rowCount(), 0, 1, 1)
|
||||
left.setRowStretch(left.rowCount()-1, 100)
|
||||
if len(ans) > 1:
|
||||
items.append(QSpacerItem(10, 100, QSizePolicy.Minimum,
|
||||
QSizePolicy.Expanding))
|
||||
right.addItem(items[-1], left.rowCount(), 0, 1, 1)
|
||||
right.setRowStretch(right.rowCount()-1, 100)
|
||||
|
||||
layout.addItem(items[-1], layout.rowCount(), 0, 1, 1)
|
||||
layout.setRowStretch(layout.rowCount()-1, 100)
|
||||
return ans, items
|
||||
|
||||
class BulkBase(Base):
|
||||
@ -342,6 +417,47 @@ class BulkRating(BulkBase, Rating):
|
||||
class BulkDateTime(BulkBase, DateTime):
|
||||
pass
|
||||
|
||||
class BulkSeries(BulkBase):
|
||||
def setup_ui(self, parent):
|
||||
values = self.all_values = list(self.db.all_custom(num=self.col_id))
|
||||
values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower()))
|
||||
w = EnComboBox(parent)
|
||||
w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon)
|
||||
w.setMinimumContentsLength(25)
|
||||
self.name_widget = w
|
||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), w]
|
||||
|
||||
self.widgets.append(QLabel(_('Automatically number books in this series'), parent))
|
||||
self.idx_widget=QCheckBox(parent)
|
||||
self.widgets.append(self.idx_widget)
|
||||
|
||||
def initialize(self, book_id):
|
||||
self.idx_widget.setChecked(False)
|
||||
for c in self.all_values:
|
||||
self.name_widget.addItem(c)
|
||||
self.name_widget.setEditText('')
|
||||
|
||||
def commit(self, book_ids, notify=False):
|
||||
val = unicode(self.name_widget.currentText()).strip()
|
||||
val = self.normalize_ui_val(val)
|
||||
update_indices = self.idx_widget.checkState()
|
||||
if val != '':
|
||||
for book_id in book_ids:
|
||||
if update_indices:
|
||||
if tweaks['series_index_auto_increment'] == 'next':
|
||||
s_index = self.db.get_next_cc_series_num_for\
|
||||
(val, num=self.col_id)
|
||||
else:
|
||||
s_index = 1.0
|
||||
else:
|
||||
s_index = self.db.get_custom_extra(book_id, num=self.col_id,
|
||||
index_is_id=True)
|
||||
self.db.set_custom(book_id, val, extra=s_index,
|
||||
num=self.col_id, notify=notify)
|
||||
|
||||
def process_each_book(self):
|
||||
return True
|
||||
|
||||
class RemoveTags(QWidget):
|
||||
|
||||
def __init__(self, parent, values):
|
||||
@ -431,35 +547,5 @@ bulk_widgets = {
|
||||
'float': BulkFloat,
|
||||
'datetime': BulkDateTime,
|
||||
'text' : BulkText,
|
||||
}
|
||||
|
||||
def populate_bulk_metadata_page(layout, db, book_ids, parent=None):
|
||||
x = db.custom_column_num_map
|
||||
cols = list(x)
|
||||
cols.sort(cmp=partial(field_sort, x=x))
|
||||
ans = []
|
||||
for i, col in enumerate(cols):
|
||||
dt = x[col]['datatype']
|
||||
if dt == 'comments':
|
||||
continue
|
||||
w = bulk_widgets[dt](db, col, parent)
|
||||
ans.append(w)
|
||||
w.initialize(book_ids)
|
||||
row = layout.rowCount()
|
||||
if len(w.widgets) == 1:
|
||||
layout.addWidget(w.widgets[0], row, 0, 1, -1)
|
||||
else:
|
||||
for c in range(0, len(w.widgets), 2):
|
||||
w.widgets[c].setBuddy(w.widgets[c+1])
|
||||
layout.addWidget(w.widgets[c], row, 0)
|
||||
layout.addWidget(w.widgets[c+1], row, 1)
|
||||
row += 1
|
||||
items = []
|
||||
if len(ans) > 0:
|
||||
items.append(QSpacerItem(10, 10, QSizePolicy.Minimum,
|
||||
QSizePolicy.Expanding))
|
||||
layout.addItem(items[-1], layout.rowCount(), 0, 1, 1)
|
||||
layout.setRowStretch(layout.rowCount()-1, 100)
|
||||
|
||||
return ans, items
|
||||
|
||||
'series': BulkSeries,
|
||||
}
|
@ -10,7 +10,7 @@ from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
|
||||
from calibre.gui2.dialogs.tag_editor import TagEditor
|
||||
from calibre.ebooks.metadata import string_to_authors, \
|
||||
authors_to_string
|
||||
from calibre.gui2.custom_column_widgets import populate_bulk_metadata_page
|
||||
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
||||
|
||||
class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
|
||||
@ -44,15 +44,14 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
self.central_widget.tabBar().setVisible(False)
|
||||
else:
|
||||
self.create_custom_column_editors()
|
||||
|
||||
self.exec_()
|
||||
|
||||
def create_custom_column_editors(self):
|
||||
w = self.central_widget.widget(1)
|
||||
layout = QGridLayout()
|
||||
|
||||
self.custom_column_widgets, self.__cc_spacers = populate_bulk_metadata_page(
|
||||
layout, self.db, self.ids, w)
|
||||
self.custom_column_widgets, self.__cc_spacers = \
|
||||
populate_metadata_page(layout, self.db, self.ids, parent=w,
|
||||
two_column=False, bulk=True)
|
||||
w.setLayout(layout)
|
||||
self.__custom_col_layouts = [layout]
|
||||
ans = self.custom_column_widgets
|
||||
|
@ -32,7 +32,7 @@ from calibre.utils.config import prefs, tweaks
|
||||
from calibre.utils.date import qt_to_dt
|
||||
from calibre.customize.ui import run_plugins_on_import, get_isbndb_key
|
||||
from calibre.gui2.dialogs.config.social import SocialMetadata
|
||||
from calibre.gui2.custom_column_widgets import populate_single_metadata_page
|
||||
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
||||
|
||||
class CoverFetcher(QThread):
|
||||
|
||||
@ -420,23 +420,19 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
|
||||
def create_custom_column_editors(self):
|
||||
w = self.central_widget.widget(1)
|
||||
top_layout = QHBoxLayout()
|
||||
top_layout.setSpacing(20)
|
||||
left_layout = QGridLayout()
|
||||
right_layout = QGridLayout()
|
||||
top_layout.addLayout(left_layout)
|
||||
|
||||
self.custom_column_widgets, self.__cc_spacers = populate_single_metadata_page(
|
||||
left_layout, right_layout, self.db, self.id, w)
|
||||
top_layout.addLayout(right_layout)
|
||||
sip.delete(w.layout())
|
||||
w.setLayout(top_layout)
|
||||
self.__custom_col_layouts = [top_layout, left_layout, right_layout]
|
||||
layout = w.layout()
|
||||
self.custom_column_widgets, self.__cc_spacers = \
|
||||
populate_metadata_page(layout, self.db, self.id,
|
||||
parent=w, bulk=False, two_column=True)
|
||||
self.__custom_col_layouts = [layout]
|
||||
ans = self.custom_column_widgets
|
||||
for i in range(len(ans)-1):
|
||||
w.setTabOrder(ans[i].widgets[-1], ans[i+1].widgets[-1])
|
||||
|
||||
|
||||
if len(ans[i+1].widgets) == 2:
|
||||
w.setTabOrder(ans[i].widgets[-1], ans[i+1].widgets[1])
|
||||
else:
|
||||
w.setTabOrder(ans[i].widgets[-1], ans[i+1].widgets[0])
|
||||
for c in range(2, len(ans[i].widgets), 2):
|
||||
w.setTabOrder(ans[i].widgets[c-1], ans[i].widgets[c+1])
|
||||
|
||||
def validate_isbn(self, isbn):
|
||||
isbn = unicode(isbn).strip()
|
||||
|
@ -173,6 +173,19 @@ class CustomColumns(object):
|
||||
ans.sort(cmp=lambda x,y:cmp(x.lower(), y.lower()))
|
||||
return ans
|
||||
|
||||
def get_custom_extra(self, idx, label=None, num=None, index_is_id=False):
|
||||
if label is not None:
|
||||
data = self.custom_column_label_map[label]
|
||||
if num is not None:
|
||||
data = self.custom_column_num_map[num]
|
||||
# add future datatypes with an extra column here
|
||||
if data['datatype'] not in ['series']:
|
||||
return None
|
||||
ign,lt = self.custom_table_names(data['num'])
|
||||
idx = idx if index_is_id else self.id(idx)
|
||||
return self.conn.get('''SELECT extra FROM %s
|
||||
WHERE book=?'''%lt, (idx,), all=False)
|
||||
|
||||
# convenience methods for tag editing
|
||||
def get_custom_items_with_ids(self, label=None, num=None):
|
||||
if label is not None:
|
||||
@ -237,7 +250,7 @@ class CustomColumns(object):
|
||||
return 1.0
|
||||
# get the label of the associated series number table
|
||||
series_num = self.conn.get('''
|
||||
SELECT MAX({lt}.s_index) FROM {lt}
|
||||
SELECT MAX({lt}.extra) FROM {lt}
|
||||
WHERE {lt}.book IN (SELECT book FROM {lt} where value=?)
|
||||
'''.format(lt=lt), (series_id,), all=False)
|
||||
if series_num is None:
|
||||
@ -343,7 +356,7 @@ class CustomColumns(object):
|
||||
(id_, xid), all=False):
|
||||
if data['datatype'] == 'series':
|
||||
self.conn.execute(
|
||||
'''INSERT INTO %s(book, value, s_index)
|
||||
'''INSERT INTO %s(book, value, extra)
|
||||
VALUES (?,?,?)'''%lt, (id_, xid, extra))
|
||||
self.data.set(id_, self.FIELD_MAP[data['num']]+1,
|
||||
extra, row_is_id=True)
|
||||
@ -401,7 +414,7 @@ class CustomColumns(object):
|
||||
custom_{num}
|
||||
'''.format(query=query%table, lt=lt, table=table, num=data['num'])
|
||||
if data['datatype'] == 'series':
|
||||
line += ''',(SELECT s_index FROM {lt} WHERE {lt}.book=books.id)
|
||||
line += ''',(SELECT extra FROM {lt} WHERE {lt}.book=books.id)
|
||||
custom_index_{num}'''.format(lt=lt, num=data['num'])
|
||||
else:
|
||||
line = '''
|
||||
@ -438,7 +451,7 @@ class CustomColumns(object):
|
||||
table, lt = self.custom_table_names(num)
|
||||
if normalized:
|
||||
if datatype == 'series':
|
||||
s_index = 's_index REAL,'
|
||||
s_index = 'extra REAL,'
|
||||
else:
|
||||
s_index = ''
|
||||
lines = [
|
||||
|
Loading…
x
Reference in New Issue
Block a user