mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
When creating custom columns allow specifying a default value to be applied to new books for that column
Fixes #1886079 [set default value [Enhancement]](https://bugs.launchpad.net/calibre/+bug/1886079) Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
300935541f
@ -92,6 +92,22 @@ def _add_newbook_tag(mi):
|
||||
mi.tags.append(tag)
|
||||
|
||||
|
||||
def _add_default_custom_column_values(mi, fm):
|
||||
cols = fm.custom_field_metadata(include_composites=False)
|
||||
for cc,col in iteritems(cols):
|
||||
dv = col['display'].get('default_value', '')
|
||||
try:
|
||||
if dv:
|
||||
if not mi.get_user_metadata(cc, make_copy=False):
|
||||
mi.set_user_metadata(cc, col)
|
||||
dt = col['datatype']
|
||||
if dt == 'datetime' and icu_lower(dv) == 'now':
|
||||
dv = nowf()
|
||||
mi.set(cc, dv)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
dynamic_category_preferences = frozenset({'grouped_search_make_user_categories', 'grouped_search_terms', 'user_categories'})
|
||||
|
||||
|
||||
@ -1571,6 +1587,7 @@ class Cache(object):
|
||||
mi.tags = list(mi.tags)
|
||||
if apply_import_tags:
|
||||
_add_newbook_tag(mi)
|
||||
_add_default_custom_column_values(mi, self.field_metadata)
|
||||
if not add_duplicates and self._has_book(mi):
|
||||
return
|
||||
series_index = (self._get_next_series_num_for(mi.series) if mi.series_index is None else mi.series_index)
|
||||
|
@ -17,6 +17,7 @@ from PyQt5.Qt import (
|
||||
)
|
||||
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.utils.date import parse_date, UNDEFINED_DATE
|
||||
from polyglot.builtins import iteritems, unicode_type, range, map
|
||||
|
||||
|
||||
@ -127,8 +128,7 @@ class CreateCustomColumn(QDialog):
|
||||
self.shortcuts.setVisible(False)
|
||||
idx = current_row
|
||||
if idx < 0:
|
||||
self.simple_error(_('No column selected'),
|
||||
_('No column has been selected'))
|
||||
self.simple_error(_('No column selected'), _('No column has been selected'))
|
||||
return
|
||||
col = current_key
|
||||
if col not in parent.custcols:
|
||||
@ -177,6 +177,24 @@ class CreateCustomColumn(QDialog):
|
||||
self.comments_type.setCurrentIndex(idx)
|
||||
elif ct == 'rating':
|
||||
self.allow_half_stars.setChecked(bool(c['display'].get('allow_half_stars', False)))
|
||||
|
||||
# Default values
|
||||
dv = c['display'].get('default_value', None)
|
||||
if dv is not None:
|
||||
if ct == 'bool':
|
||||
self.default_value.setText(_('Yes') if dv else _('No'))
|
||||
elif ct == 'datetime':
|
||||
self.default_value.setText(_('Now') if dv == 'now' else dv)
|
||||
elif ct == 'rating':
|
||||
if self.allow_half_stars.isChecked():
|
||||
self.default_value.setText(unicode_type(dv/2))
|
||||
else:
|
||||
self.default_value.setText(unicode_type(dv//2))
|
||||
elif ct in ('int', 'float'):
|
||||
self.default_value.setText(unicode_type(dv))
|
||||
elif ct not in ('composite', '*composite'):
|
||||
self.default_value.setText(dv)
|
||||
|
||||
self.datatype_changed()
|
||||
if ct in ['text', 'composite', 'enumeration']:
|
||||
self.use_decorations.setChecked(c['display'].get('use_decorations', False))
|
||||
@ -390,6 +408,15 @@ class CreateCustomColumn(QDialog):
|
||||
l.addWidget(cch)
|
||||
add_row(None, l)
|
||||
|
||||
# Default value
|
||||
self.default_value = dv = QLineEdit(self)
|
||||
dv.setToolTip('<p>' + _('Default value when a new book is added to the '
|
||||
'library. For Date columns enter the word "Now", or the date as '
|
||||
'yyyy-mm-dd. For Yes/No columns enter "Yes" "No". For Text with '
|
||||
'a fixed set of values enter one of the permitted values. For '
|
||||
'Rating columns enter a number between 0 and 5.') + '</p>')
|
||||
self.default_value_label = add_row(_('Default value'), dv)
|
||||
|
||||
self.resize(self.sizeHint())
|
||||
# }}}
|
||||
|
||||
@ -456,6 +483,8 @@ class CreateCustomColumn(QDialog):
|
||||
getattr(self, 'composite_'+x).setVisible(col_type in ['composite', '*composite'])
|
||||
for x in ('box', 'default_label', 'label', 'colors', 'colors_label'):
|
||||
getattr(self, 'enum_'+x).setVisible(col_type == 'enumeration')
|
||||
for x in ('value_label', 'value'):
|
||||
getattr(self, 'default_'+x).setVisible(col_type not in ['composite', '*composite'])
|
||||
self.use_decorations.setVisible(col_type in ['text', 'composite', 'enumeration'])
|
||||
self.is_names.setVisible(col_type == '*text')
|
||||
is_comments = col_type == 'comments'
|
||||
@ -512,15 +541,30 @@ class CreateCustomColumn(QDialog):
|
||||
|
||||
display_dict = {}
|
||||
|
||||
default_val = (unicode_type(self.default_value.text()).strip()
|
||||
if col_type != 'composite' else None)
|
||||
|
||||
if col_type == 'datetime':
|
||||
if unicode_type(self.format_box.text()).strip():
|
||||
display_dict = {'date_format':unicode_type(self.format_box.text()).strip()}
|
||||
else:
|
||||
display_dict = {'date_format': None}
|
||||
if default_val:
|
||||
if default_val == _('Now'):
|
||||
display_dict['default_value'] = 'now'
|
||||
else:
|
||||
try:
|
||||
tv = parse_date(default_val)
|
||||
except:
|
||||
tv = UNDEFINED_DATE
|
||||
if tv == UNDEFINED_DATE:
|
||||
return self.simple_error(_('Invalid default value'),
|
||||
_('The default value must be "Now" or a date'))
|
||||
display_dict['default_value'] = default_val
|
||||
elif col_type == 'composite':
|
||||
if not unicode_type(self.composite_box.text()).strip():
|
||||
return self.simple_error('', _('You must enter a template for'
|
||||
' composite columns'))
|
||||
return self.simple_error('', _('You must enter a template for '
|
||||
'composite columns'))
|
||||
display_dict = {'composite_template':unicode_type(self.composite_box.text()).strip(),
|
||||
'composite_sort': ['text', 'number', 'date', 'bool']
|
||||
[self.composite_sort_by.currentIndex()],
|
||||
@ -529,8 +573,8 @@ class CreateCustomColumn(QDialog):
|
||||
}
|
||||
elif col_type == 'enumeration':
|
||||
if not unicode_type(self.enum_box.text()).strip():
|
||||
return self.simple_error('', _('You must enter at least one'
|
||||
' value for enumeration columns'))
|
||||
return self.simple_error('', _('You must enter at least one '
|
||||
'value for enumeration columns'))
|
||||
l = [v.strip() for v in unicode_type(self.enum_box.text()).split(',') if v.strip()]
|
||||
l_lower = [v.lower() for v in l]
|
||||
for i,v in enumerate(l_lower):
|
||||
@ -544,13 +588,16 @@ class CreateCustomColumn(QDialog):
|
||||
c = []
|
||||
if len(c) != 0 and len(c) != len(l):
|
||||
return self.simple_error('', _('The colors box must be empty or '
|
||||
'contain the same number of items as the value box'))
|
||||
'contain the same number of items as the value box'))
|
||||
for tc in c:
|
||||
if tc not in QColor.colorNames() and not re.match("#(?:[0-9a-f]{3}){1,4}",tc,re.I):
|
||||
return self.simple_error('',
|
||||
_('The color {0} is unknown').format(tc))
|
||||
|
||||
return self.simple_error('', _('The color {0} is unknown').format(tc))
|
||||
display_dict = {'enum_values': l, 'enum_colors': c}
|
||||
if default_val:
|
||||
if default_val not in l:
|
||||
return self.simple_error(_('Invalid default value'),
|
||||
_('The default value must be one of the permitted values'))
|
||||
display_dict['default_value'] = default_val
|
||||
elif col_type == 'text' and is_multiple:
|
||||
display_dict = {'is_names': self.is_names.isChecked()}
|
||||
elif col_type in ['int', 'float']:
|
||||
@ -558,14 +605,51 @@ class CreateCustomColumn(QDialog):
|
||||
display_dict = {'number_format':unicode_type(self.format_box.text()).strip()}
|
||||
else:
|
||||
display_dict = {'number_format': None}
|
||||
if default_val:
|
||||
try:
|
||||
if col_type == 'int':
|
||||
msg = _('The default value must be an integer')
|
||||
tv = int(default_val)
|
||||
display_dict['default_value'] = tv
|
||||
else:
|
||||
msg = _('The default value must be a real number')
|
||||
tv = float(default_val)
|
||||
display_dict['default_value'] = tv
|
||||
except:
|
||||
return self.simple_error(_('Invalid default value'), msg)
|
||||
elif col_type == 'comments':
|
||||
display_dict['heading_position'] = unicode_type(self.comments_heading_position.currentData())
|
||||
display_dict['interpret_as'] = unicode_type(self.comments_type.currentData())
|
||||
elif col_type == 'rating':
|
||||
display_dict['allow_half_stars'] = bool(self.allow_half_stars.isChecked())
|
||||
half_stars = bool(self.allow_half_stars.isChecked())
|
||||
display_dict['allow_half_stars'] = half_stars
|
||||
if default_val:
|
||||
try:
|
||||
tv = int((float(default_val) if half_stars else int(default_val)) * 2)
|
||||
except:
|
||||
tv = -1
|
||||
if tv < 0 or tv > 10:
|
||||
if half_stars:
|
||||
return self.simple_error(_('Invalid default value'),
|
||||
_('The default value must be a real number between 0 and 5.0'))
|
||||
else:
|
||||
return self.simple_error(_('Invalid default value'),
|
||||
_('The default value must be an integer between 0 and 5'))
|
||||
display_dict['default_value'] = tv
|
||||
elif col_type == 'bool':
|
||||
if default_val:
|
||||
tv = {_('Yes'): True, _('No'): False}.get(default_val, None)
|
||||
if tv is None:
|
||||
return self.simple_error(_('Invalid default value'),
|
||||
_('The default value must be "Yes" or "No"'))
|
||||
display_dict['default_value'] = tv
|
||||
|
||||
if col_type in ['text', 'composite', 'enumeration'] and not is_multiple:
|
||||
display_dict['use_decorations'] = self.use_decorations.checkState()
|
||||
|
||||
if default_val and 'default_value' not in display_dict:
|
||||
display_dict['default_value'] = default_val
|
||||
|
||||
display_dict['description'] = self.description_box.text().strip()
|
||||
|
||||
if not self.editing_col:
|
||||
|
Loading…
x
Reference in New Issue
Block a user