mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Enumeration type custom columns
This commit is contained in:
parent
438e0d5305
commit
5cdc87fc89
@ -15,7 +15,7 @@ from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \
|
|||||||
|
|
||||||
from calibre.utils.date import qt_to_dt, now
|
from calibre.utils.date import qt_to_dt, now
|
||||||
from calibre.gui2.widgets import TagsLineEdit, EnComboBox
|
from calibre.gui2.widgets import TagsLineEdit, EnComboBox
|
||||||
from calibre.gui2 import UNDEFINED_QDATE
|
from calibre.gui2 import UNDEFINED_QDATE, error_dialog
|
||||||
from calibre.utils.config import tweaks
|
from calibre.utils.config import tweaks
|
||||||
|
|
||||||
class Base(object):
|
class Base(object):
|
||||||
@ -313,22 +313,29 @@ class Series(Base):
|
|||||||
class Enumeration(Base):
|
class Enumeration(Base):
|
||||||
|
|
||||||
def setup_ui(self, parent):
|
def setup_ui(self, parent):
|
||||||
|
self.parent = parent
|
||||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||||
QComboBox(parent)]
|
QComboBox(parent)]
|
||||||
w = self.widgets[1]
|
w = self.widgets[1]
|
||||||
vals = self.col_metadata['display']['enum_values']
|
vals = self.col_metadata['display']['enum_values']
|
||||||
w.addItem('')
|
|
||||||
for v in vals:
|
for v in vals:
|
||||||
w.addItem(v)
|
w.addItem(v)
|
||||||
|
|
||||||
def initialize(self, book_id):
|
def initialize(self, book_id):
|
||||||
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
||||||
if val is None:
|
if val is None:
|
||||||
val = ''
|
# This really shouldn't happen
|
||||||
|
val = self.col_metadata['display']['enum_values'][0]
|
||||||
self.initial_val = val
|
self.initial_val = val
|
||||||
val = self.normalize_db_val(val)
|
val = self.normalize_db_val(val)
|
||||||
idx = self.widgets[1].findText(val)
|
idx = self.widgets[1].findText(val)
|
||||||
if idx < 0:
|
if idx < 0:
|
||||||
|
error_dialog(self.parent, '',
|
||||||
|
_('The enumeration "{0}" contains an invalid value '
|
||||||
|
'that will be set to the default').format(
|
||||||
|
self.col_metadata['name']),
|
||||||
|
show=True, show_copy_button=False)
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
self.widgets[1].setCurrentIndex(idx)
|
self.widgets[1].setCurrentIndex(idx)
|
||||||
|
|
||||||
@ -586,20 +593,33 @@ class BulkEnumeration(BulkBase, Enumeration):
|
|||||||
|
|
||||||
def get_initial_value(self, book_ids):
|
def get_initial_value(self, book_ids):
|
||||||
value = None
|
value = None
|
||||||
|
ret_value = None
|
||||||
|
dialog_shown = False
|
||||||
for book_id in book_ids:
|
for book_id in book_ids:
|
||||||
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
|
||||||
if value is not None and value != val:
|
if val not in self.col_metadata['display']['enum_values']:
|
||||||
return ' nochange '
|
if not dialog_shown:
|
||||||
|
error_dialog(self.parent, '',
|
||||||
|
_('The enumeration "{0}" contains invalid values '
|
||||||
|
'that will not appear in the list').format(
|
||||||
|
self.col_metadata['name']),
|
||||||
|
show=True, show_copy_button=False)
|
||||||
|
dialog_shown = True
|
||||||
|
ret_value = ' nochange '
|
||||||
|
elif value is not None and value != val:
|
||||||
|
ret_value = ' nochange '
|
||||||
value = val
|
value = val
|
||||||
return value
|
if ret_value is None:
|
||||||
|
return value
|
||||||
|
return ret_value
|
||||||
|
|
||||||
def setup_ui(self, parent):
|
def setup_ui(self, parent):
|
||||||
|
self.parent = parent
|
||||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||||
QComboBox(parent)]
|
QComboBox(parent)]
|
||||||
w = self.widgets[1]
|
w = self.widgets[1]
|
||||||
vals = self.col_metadata['display']['enum_values']
|
vals = self.col_metadata['display']['enum_values']
|
||||||
w.addItem('Do Not Change')
|
w.addItem('Do Not Change')
|
||||||
w.addItem('')
|
|
||||||
for v in vals:
|
for v in vals:
|
||||||
w.addItem(v)
|
w.addItem(v)
|
||||||
|
|
||||||
@ -620,14 +640,10 @@ class BulkEnumeration(BulkBase, Enumeration):
|
|||||||
if val != self.initial_val and val != ' nochange ':
|
if val != self.initial_val and val != ' nochange ':
|
||||||
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify)
|
||||||
|
|
||||||
def normalize_ui_val(self, val):
|
|
||||||
if val == '':
|
|
||||||
return None
|
|
||||||
return val
|
|
||||||
|
|
||||||
def normalize_db_val(self, val):
|
def normalize_db_val(self, val):
|
||||||
if val is None:
|
if val is None:
|
||||||
return ''
|
# this really shouldn't happen
|
||||||
|
val = self.col_metadata['display']['enum_values'][0]
|
||||||
return val
|
return val
|
||||||
|
|
||||||
class RemoveTags(QWidget):
|
class RemoveTags(QWidget):
|
||||||
|
@ -262,9 +262,7 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
|
|||||||
def createEditor(self, parent, option, index):
|
def createEditor(self, parent, option, index):
|
||||||
m = index.model()
|
m = index.model()
|
||||||
col = m.column_map[index.column()]
|
col = m.column_map[index.column()]
|
||||||
print 'delegate'
|
|
||||||
editor = QComboBox(parent)
|
editor = QComboBox(parent)
|
||||||
editor.addItem('')
|
|
||||||
for v in m.custom_columns[col]['display']['enum_values']:
|
for v in m.custom_columns[col]['display']['enum_values']:
|
||||||
editor.addItem(v)
|
editor.addItem(v)
|
||||||
return editor
|
return editor
|
||||||
@ -272,14 +270,20 @@ class CcEnumDelegate(QStyledItemDelegate): # {{{
|
|||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
val = unicode(editor.currentText())
|
val = unicode(editor.currentText())
|
||||||
if val == '':
|
if val == '':
|
||||||
val = None
|
# This shouldn't happen ...
|
||||||
|
m = index.model()
|
||||||
|
col = m.column_map[index.column()]
|
||||||
|
val = m.custom_columns[col]['display']['enum_values'][0]
|
||||||
model.setData(index, QVariant(val), Qt.EditRole)
|
model.setData(index, QVariant(val), Qt.EditRole)
|
||||||
|
|
||||||
def setEditorData(self, editor, index):
|
def setEditorData(self, editor, index):
|
||||||
m = index.model()
|
m = index.model()
|
||||||
val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']]
|
val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']]
|
||||||
if val is None:
|
if val is None:
|
||||||
val = ''
|
# This shouldn't happen
|
||||||
|
m = index.model()
|
||||||
|
col = m.column_map[index.column()]
|
||||||
|
val = m.custom_columns[col]['display']['enum_values'][0]
|
||||||
idx = editor.findText(val)
|
idx = editor.findText(val)
|
||||||
if idx < 0:
|
if idx < 0:
|
||||||
editor.setCurrentIndex(0)
|
editor.setCurrentIndex(0)
|
||||||
|
@ -212,7 +212,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="enum_box">
|
<widget class="QLineEdit" name="enum_box">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>A comma-separated list of permitted values. The empty value is always permitted</string>
|
<string>A comma-separated list of permitted values. The first value is the default</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
@ -228,7 +228,7 @@
|
|||||||
<string>Default: (nothing)</string>
|
<string>Default: (nothing)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Note that the empty value is always permitted, but is not shown in the list</string>
|
<string>The first value entered will be the default value for this enumeration</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -177,6 +177,8 @@ class CustomColumns(object):
|
|||||||
ans = ans.split('|') if ans else []
|
ans = ans.split('|') if ans else []
|
||||||
if data['display'].get('sort_alpha', False):
|
if data['display'].get('sort_alpha', False):
|
||||||
ans.sort(cmp=lambda x,y:cmp(x.lower(), y.lower()))
|
ans.sort(cmp=lambda x,y:cmp(x.lower(), y.lower()))
|
||||||
|
elif data['datatype'] == 'enumeration' and ans is None:
|
||||||
|
ans = data['display']['enum_values'][0]
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def get_custom_extra(self, idx, label=None, num=None, index_is_id=False):
|
def get_custom_extra(self, idx, label=None, num=None, index_is_id=False):
|
||||||
@ -442,7 +444,6 @@ class CustomColumns(object):
|
|||||||
if data['normalized']:
|
if data['normalized']:
|
||||||
if data['datatype'] == 'enumeration' and \
|
if data['datatype'] == 'enumeration' and \
|
||||||
val not in data['display']['enum_values']:
|
val not in data['display']['enum_values']:
|
||||||
print 'attempt to set enum to', val
|
|
||||||
return None
|
return None
|
||||||
if not append or not data['is_multiple']:
|
if not append or not data['is_multiple']:
|
||||||
self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,))
|
self.conn.execute('DELETE FROM %s WHERE book=?'%lt, (id_,))
|
||||||
@ -524,18 +525,30 @@ class CustomColumns(object):
|
|||||||
display = data['display']
|
display = data['display']
|
||||||
table, lt = self.custom_table_names(data['num'])
|
table, lt = self.custom_table_names(data['num'])
|
||||||
if data['normalized']:
|
if data['normalized']:
|
||||||
query = '%s.value'
|
if data['datatype'] == 'enumeration':
|
||||||
if data['is_multiple']:
|
query = '%s.value'
|
||||||
query = 'group_concat(%s.value, "|")'
|
line = '''
|
||||||
if not display.get('sort_alpha', False):
|
val_for_enum(\'
|
||||||
query = 'sort_concat(link.id, %s.value)'
|
SELECT {table}.value FROM {lt}
|
||||||
line = '''(SELECT {query} FROM {lt} AS link INNER JOIN
|
AS link INNER JOIN {table} ON(link.value={table}.id)
|
||||||
{table} ON(link.value={table}.id) WHERE link.book=books.id)
|
WHERE link.book=?\',
|
||||||
custom_{num}
|
\'{default}\', books.id) custom_{num}
|
||||||
'''.format(query=query%table, lt=lt, table=table, num=data['num'])
|
'''.format(lt=lt, table=table,
|
||||||
if data['datatype'] == 'series':
|
default=data['display']['enum_values'][0],
|
||||||
line += ''',(SELECT extra FROM {lt} WHERE {lt}.book=books.id)
|
num=data['num'])
|
||||||
custom_index_{num}'''.format(lt=lt, num=data['num'])
|
else:
|
||||||
|
query = '%s.value'
|
||||||
|
if data['is_multiple']:
|
||||||
|
query = 'group_concat(%s.value, "|")'
|
||||||
|
if not display.get('sort_alpha', False):
|
||||||
|
query = 'sort_concat(link.id, %s.value)'
|
||||||
|
line = '''(SELECT {query} FROM {lt} AS link INNER JOIN
|
||||||
|
{table} ON(link.value={table}.id) WHERE link.book=books.id)
|
||||||
|
custom_{num}
|
||||||
|
'''.format(query=query%table, lt=lt, table=table, num=data['num'])
|
||||||
|
if data['datatype'] == 'series':
|
||||||
|
line += ''',(SELECT extra FROM {lt} WHERE {lt}.book=books.id)
|
||||||
|
custom_index_{num}'''.format(lt=lt, num=data['num'])
|
||||||
else:
|
else:
|
||||||
line = '''
|
line = '''
|
||||||
(SELECT value FROM {table} WHERE book=books.id) custom_{num}
|
(SELECT value FROM {table} WHERE book=books.id) custom_{num}
|
||||||
|
@ -115,6 +115,17 @@ def pynocase(one, two, encoding='utf-8'):
|
|||||||
pass
|
pass
|
||||||
return cmp(one.lower(), two.lower())
|
return cmp(one.lower(), two.lower())
|
||||||
|
|
||||||
|
def enum_col_value(select, def_val, id, conn=None):
|
||||||
|
try:
|
||||||
|
v = conn.get(select, (id,), all=False)
|
||||||
|
if v is None:
|
||||||
|
v = def_val
|
||||||
|
except Exception, e:
|
||||||
|
if DEBUG:
|
||||||
|
print 'enum_col_value failed'
|
||||||
|
print e
|
||||||
|
v = def_val
|
||||||
|
return v
|
||||||
|
|
||||||
def load_c_extensions(conn, debug=DEBUG):
|
def load_c_extensions(conn, debug=DEBUG):
|
||||||
try:
|
try:
|
||||||
@ -165,6 +176,8 @@ class DBThread(Thread):
|
|||||||
self.conn.create_function('author_to_author_sort', 1,
|
self.conn.create_function('author_to_author_sort', 1,
|
||||||
_author_to_author_sort)
|
_author_to_author_sort)
|
||||||
self.conn.create_function('uuid4', 0, lambda : str(uuid.uuid4()))
|
self.conn.create_function('uuid4', 0, lambda : str(uuid.uuid4()))
|
||||||
|
self.conn.create_function('val_for_enum', 3,
|
||||||
|
partial(enum_col_value, conn=self.conn))
|
||||||
# Dummy functions for dynamically created filters
|
# Dummy functions for dynamically created filters
|
||||||
self.conn.create_function('books_list_filter', 1, lambda x: 1)
|
self.conn.create_function('books_list_filter', 1, lambda x: 1)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user