diff --git a/src/calibre/db/cli/cmd_add_custom_column.py b/src/calibre/db/cli/cmd_add_custom_column.py index 2f6f22ae56..3cad3997a1 100644 --- a/src/calibre/db/cli/cmd_add_custom_column.py +++ b/src/calibre/db/cli/cmd_add_custom_column.py @@ -4,19 +4,89 @@ from __future__ import absolute_import, division, print_function, unicode_literals +import json + +from calibre import prints +from calibre.db.legacy import LibraryDatabase +from calibre.library.custom_columns import CustomColumns + readonly = False version = 0 # change this if you change signature of implementation() +no_remote = True def implementation(db, notify_changes, *args): - is_remote = notify_changes is not None - is_remote + raise NotImplementedError() def option_parser(get_parser, args): - pass + parser = get_parser( + _( + '''\ +%prog add_custom_column [options] label name datatype + +Create a custom column. label is the machine friendly name of the column. Should +not contain spaces or colons. name is the human friendly name of the column. +datatype is one of: {0} +''' + ).format(', '.join(sorted(CustomColumns.CUSTOM_DATA_TYPES))) + ) + + parser.add_option( + '--is-multiple', + default=False, + action='store_true', + help=_( + 'This column stores tag like data (i.e. ' + 'multiple comma separated values). Only ' + 'applies if datatype is text.' + ) + ) + parser.add_option( + '--display', + default='{}', + help=_( + 'A dictionary of options to customize how ' + 'the data in this column will be interpreted. This is a JSON ' + ' string. For enumeration columns, use ' + '--display="{\\"enum_values\\":[\\"val1\\", \\"val2\\"]}"' + '\n' + 'There are many options that can go into the display variable.' + 'The options by column type are:\n' + 'composite: composite_template, composite_sort, make_category,' + 'contains_html, use_decorations\n' + 'datetime: date_format\n' + 'enumeration: enum_values, enum_colors, use_decorations\n' + 'int, float: number_format\n' + 'text: is_names, use_decorations\n' + '\n' + 'The best way to find legal combinations is to create a custom ' + 'column of the appropriate type in the GUI then look at the ' + 'backup OPF for a book (ensure that a new OPF has been created ' + 'since the column was added). You will see the JSON for the ' + '"display" for the new column in the OPF.' + ) + ) + return parser + + +def do_add_custom_column(db, label, name, datatype, is_multiple, display): + num = db.create_custom_column( + label, name, datatype, is_multiple, display=display + ) + prints('Custom column created with id: %s' % num) def main(opts, args, dbctx): - raise NotImplementedError('TODO: implement this') + if len(args) < 3: + raise SystemExit(_('You must specify label, name and datatype')) + do_add_custom_column( + dbctx.db, args[0], args[1], args[2], opts.is_multiple, + json.loads(opts.display) + ) + # Update the stored field_metadata + dbctx.db.close() + db = LibraryDatabase(dbctx.db.library_path) + m = db.field_metadata.all_metadata() + db.new_api.set_pref('field_metadata', m) return 0 diff --git a/src/calibre/db/cli/cmd_custom_columns.py b/src/calibre/db/cli/cmd_custom_columns.py index 2f6f22ae56..0e8a0b5813 100644 --- a/src/calibre/db/cli/cmd_custom_columns.py +++ b/src/calibre/db/cli/cmd_custom_columns.py @@ -4,19 +4,45 @@ from __future__ import absolute_import, division, print_function, unicode_literals -readonly = False +from pprint import pformat + +from calibre import prints + +readonly = True version = 0 # change this if you change signature of implementation() def implementation(db, notify_changes, *args): - is_remote = notify_changes is not None - is_remote + return db.backend.custom_column_label_map def option_parser(get_parser, args): - pass + parser = get_parser( + _( + '''\ +%prog custom_columns [options] + +List available custom columns. Shows column labels and ids. + ''' + ) + ) + parser.add_option( + '-d', + '--details', + default=False, + action='store_true', + help=_('Show details for each column.') + ) + return parser def main(opts, args, dbctx): - raise NotImplementedError('TODO: implement this') + for col, data in dbctx.run('custom_columns').iteritems(): + if opts.details: + prints(col) + print() + prints(pformat(data)) + print('\n') + else: + prints(col, '(%d)'%data['num']) return 0 diff --git a/src/calibre/db/cli/cmd_remove_custom_column.py b/src/calibre/db/cli/cmd_remove_custom_column.py index 2f6f22ae56..d137440538 100644 --- a/src/calibre/db/cli/cmd_remove_custom_column.py +++ b/src/calibre/db/cli/cmd_remove_custom_column.py @@ -4,19 +4,67 @@ from __future__ import absolute_import, division, print_function, unicode_literals +from calibre import prints +from calibre.db.legacy import LibraryDatabase + readonly = False version = 0 # change this if you change signature of implementation() +no_remote = True def implementation(db, notify_changes, *args): - is_remote = notify_changes is not None - is_remote + raise NotImplementedError() def option_parser(get_parser, args): - pass + parser = get_parser( + _( + '''\ +%prog remove_custom_column [options] label + +Remove the custom column identified by label. You can see available +columns with the custom_columns command. + ''' + ) + ) + parser.add_option( + '-f', + '--force', + default=False, + action='store_true', + help=_('Do not ask for confirmation') + ) + return parser + + +def do_remove_custom_column(db, label, force): + if not force: + q = raw_input( + _('You will lose all data in the column: %s.' + ' Are you sure (y/n)? ') % label + ) + if q.lower().strip() != _('y'): + return + try: + db.delete_custom_column(label=label) + except KeyError: + raise SystemExit( + _( + 'No column named %s found. You must use column labels, not titles.' + ' Use calibredb custom_columns to get a list of labels.' + ) % label + ) + prints('Column %r removed.' % label) def main(opts, args, dbctx): - raise NotImplementedError('TODO: implement this') + if len(args) < 1: + raise SystemExit(_('Error: You must specify a column label')) + + do_remove_custom_column(dbctx.db, args[0], opts.force) + # Update the stored field_metadata + dbctx.db.close() + db = LibraryDatabase(dbctx.db.library_path) + m = db.field_metadata.all_metadata() + db.new_api.set_pref('field_metadata', m) return 0 diff --git a/src/calibre/db/cli/main.py b/src/calibre/db/cli/main.py index 035eac26d8..40e48619d3 100644 --- a/src/calibre/db/cli/main.py +++ b/src/calibre/db/cli/main.py @@ -20,10 +20,9 @@ from calibre.utils.serialize import MSGPACK_MIME COMMANDS = ( 'list', 'add', 'remove', 'add_format', 'remove_format', 'show_metadata', - 'set_metadata', 'export', 'catalog', - 'saved_searches', - # 'add_custom_column', - # 'custom_columns', 'remove_custom_column', 'set_custom', 'restore_database', + 'set_metadata', 'export', 'catalog', 'saved_searches', 'add_custom_column', + 'custom_columns', 'remove_custom_column', + # 'set_custom', 'restore_database', # 'check_library', 'list_categories', 'backup_metadata', 'clone', 'embed_metadata', # 'search' ) diff --git a/src/calibre/db/legacy.py b/src/calibre/db/legacy.py index b9b676b39f..f5b6aa2b98 100644 --- a/src/calibre/db/legacy.py +++ b/src/calibre/db/legacy.py @@ -695,7 +695,7 @@ class LibraryDatabase(object): self.new_api.delete_custom_column(label, num) def create_custom_column(self, label, name, datatype, is_multiple, editable=True, display={}): - self.new_api.create_custom_column(label, name, datatype, is_multiple, editable=editable, display=display) + return self.new_api.create_custom_column(label, name, datatype, is_multiple, editable=editable, display=display) def set_custom_column_metadata(self, num, name=None, label=None, is_editable=None, display=None, notify=True, update_last_modified=False):