From 8e1365061c4db7531428eeff9e0f9c9b9f68b936 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 4 Jun 2011 19:56:38 +0100 Subject: [PATCH 1/2] Add is_multiple migration to device json codec. Make opf and the codec share code. --- .../ebooks/metadata/book/json_codec.py | 51 ++++++++++++++++--- src/calibre/ebooks/metadata/opf2.py | 35 +++---------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/calibre/ebooks/metadata/book/json_codec.py b/src/calibre/ebooks/metadata/book/json_codec.py index 1d93b5dece..1b0768ab69 100644 --- a/src/calibre/ebooks/metadata/book/json_codec.py +++ b/src/calibre/ebooks/metadata/book/json_codec.py @@ -5,8 +5,7 @@ Created on 4 Jun 2010 ''' from base64 import b64encode, b64decode -import json -import traceback +import json, traceback from calibre.ebooks.metadata.book import SERIALIZABLE_FIELDS from calibre.constants import filesystem_encoding, preferred_encoding @@ -69,6 +68,40 @@ def object_to_unicode(obj, enc=preferred_encoding): return ans return obj +def encode_is_multiple(fm): + if fm.get('is_multiple'): + # migrate is_multiple back to a character + fm['is_multiple2'] = fm.get('is_multiple', {}) + dt = fm.get('datatype', None) + if dt == 'composite': + fm['is_multiple'] = ',' + else: + fm['is_multiple'] = '|' + else: + fm['is_multiple'] = None + fm['is_multiple2'] = {} + +def decode_is_multiple(fm): + im = fm.get('is_multiple2', None) + if im: + fm['is_multiple'] = im + del fm['is_multiple2'] + else: + # Must migrate the is_multiple from char to dict + im = fm.get('is_multiple', {}) + if im: + dt = fm.get('datatype', None) + if dt == 'composite': + im = {'cache_to_list': ',', 'ui_to_list': ',', + 'list_to_ui': ', '} + elif fm.get('display', {}).get('is_names', False): + im = {'cache_to_list': '|', 'ui_to_list': '&', + 'list_to_ui': ', '} + else: + im = {'cache_to_list': '|', 'ui_to_list': ',', + 'list_to_ui': ', '} + fm['is_multiple'] = im + class JsonCodec(object): def __init__(self): @@ -93,9 +126,10 @@ class JsonCodec(object): def encode_metadata_attr(self, book, key): if key == 'user_metadata': meta = book.get_all_user_metadata(make_copy=True) - for k in meta: - if meta[k]['datatype'] == 'datetime': - meta[k]['#value#'] = datetime_to_string(meta[k]['#value#']) + for fm in meta.itervalues(): + if fm['datatype'] == 'datetime': + fm['#value#'] = datetime_to_string(fm['#value#']) + encode_is_multiple(fm) return meta if key in self.field_metadata: datatype = self.field_metadata[key]['datatype'] @@ -135,9 +169,10 @@ class JsonCodec(object): if key == 'classifiers': key = 'identifiers' if key == 'user_metadata': - for k in value: - if value[k]['datatype'] == 'datetime': - value[k]['#value#'] = string_to_datetime(value[k]['#value#']) + for fm in value.itervalues(): + if fm['datatype'] == 'datetime': + fm['#value#'] = string_to_datetime(fm['#value#']) + decode_is_multiple(fm) return value elif key in self.field_metadata: if self.field_metadata[key]['datatype'] == 'datetime': diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py index 82e5127b59..80fb84633b 100644 --- a/src/calibre/ebooks/metadata/opf2.py +++ b/src/calibre/ebooks/metadata/opf2.py @@ -453,19 +453,13 @@ class TitleSortField(MetadataField): def serialize_user_metadata(metadata_elem, all_user_metadata, tail='\n'+(' '*8)): from calibre.utils.config import to_json - from calibre.ebooks.metadata.book.json_codec import object_to_unicode + from calibre.ebooks.metadata.book.json_codec import (object_to_unicode, + encode_is_multiple) for name, fm in all_user_metadata.items(): try: - if fm.get('is_multiple'): - # migrate is_multiple back to a character - fm = copy.copy(fm) - fm['is_multiple2'] = fm.get('is_multiple', {}) - dt = fm.get('datatype', None) - if dt == 'composite': - fm['is_multiple'] = ',' - else: - fm['is_multiple'] = '|' + fm = copy.copy(fm) + encode_is_multiple(fm) fm = object_to_unicode(fm) fm = json.dumps(fm, default=to_json, ensure_ascii=False) except: @@ -584,6 +578,7 @@ class OPF(object): # {{{ self._user_metadata_ = {} temp = Metadata('x', ['x']) from calibre.utils.config import from_json + from calibre.ebooks.metadata.book.json_codec import decode_is_multiple elems = self.root.xpath('//*[name() = "meta" and starts-with(@name,' '"calibre:user_metadata:") and @content]') for elem in elems: @@ -594,25 +589,7 @@ class OPF(object): # {{{ fm = elem.get('content') try: fm = json.loads(fm, object_hook=from_json) - im = fm.get('is_multiple2', None) - if im: - fm['is_multiple'] = im - del fm['is_multiple2'] - else: - # Must migrate the is_multiple from char to dict - im = fm.get('is_multiple', None) - if im: - dt = fm.get('datatype', None) - if dt == 'composite': - im = {'cache_to_list': ',', 'ui_to_list': ',', - 'list_to_ui': ', '} - elif fm.get('display', {}).get('is_names', False): - im = {'cache_to_list': '|', 'ui_to_list': '&', - 'list_to_ui': ', '} - else: - im = {'cache_to_list': '|', 'ui_to_list': ',', - 'list_to_ui': ', '} - fm['is_multiple'] = im + decode_is_multiple(fm) temp.set_user_metadata(name, fm) except: prints('Failed to read user metadata:', name) From 5042169987ab6cd529832af422bb987bdf05578f Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 4 Jun 2011 20:08:03 +0100 Subject: [PATCH 2/2] Fix #792864 - cannot edit none-valued number columns --- src/calibre/gui2/library/delegates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index b97cb3074a..02f7452694 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -288,6 +288,8 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{ def setEditorData(self, editor, index): m = index.model() val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']] + if val is None: + val = 0 editor.setValue(val) # }}}