This commit is contained in:
Kovid Goyal 2010-09-13 10:47:06 -06:00
commit e65d2f24bb
5 changed files with 102 additions and 47 deletions

View File

@ -12,7 +12,6 @@ from calibre.devices.interface import BookList as _BookList
from calibre.constants import preferred_encoding
from calibre import isbytestring
from calibre.utils.config import prefs, tweaks
from calibre.utils.date import format_date
class Book(Metadata):
def __init__(self, prefix, lpath, size=None, other=None):
@ -105,21 +104,7 @@ class CollectionsBookList(BookList):
attr_name = ''
elif attr_name != '':
attr_name = '(%s)'%attr_name
if attr not in cust_field_meta:
cat_name = '%s %s'%(category, attr_name)
else:
fm = cust_field_meta[attr]
if fm['datatype'] == 'bool':
if category:
cat_name = '%s %s'%(_('Yes'), attr_name)
else:
cat_name = '%s %s'%(_('No'), attr_name)
elif fm['datatype'] == 'datetime':
cat_name = '%s %s'%(format_date(category,
fm['display'].get('date_format','dd MMM yyyy')), attr_name)
else:
cat_name = '%s %s'%(category, attr_name)
cat_name = '%s %s'%(category, attr_name)
return cat_name.strip()
def get_collections(self, collection_attributes):
@ -156,7 +141,7 @@ class CollectionsBookList(BookList):
cust_field_meta = book.get_all_user_metadata(make_copy=False)
for attr in attrs:
attr = attr.strip()
val = meta_vals.get(attr, None)
ign, val = book.format_field(attr, ignore_series_index=True)
if not val: continue
if isbytestring(val):
val = val.decode(preferred_encoding, 'replace')

View File

@ -101,16 +101,23 @@ STANDARD_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union(
DEVICE_METADATA_FIELDS).union(
CALIBRE_METADATA_FIELDS)
# Metadata fields that smart update must do special processing to copy.
SC_FIELDS_NOT_COPIED = frozenset(['title', 'title_sort', 'authors',
'author_sort', 'author_sort_map',
'cover_data', 'tags', 'language'])
# Metadata fields that smart update should copy only if the source is not None
SC_FIELDS_COPY_NOT_NULL = frozenset(['lpath', 'size', 'comments', 'thumbnail'])
# Metadata fields that smart update should copy without special handling
COPYABLE_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union(
SC_COPYABLE_FIELDS = SOCIAL_METADATA_FIELDS.union(
PUBLICATION_METADATA_FIELDS).union(
BOOK_STRUCTURE_FIELDS).union(
DEVICE_METADATA_FIELDS).union(
CALIBRE_METADATA_FIELDS) - \
frozenset(['title', 'title_sort', 'authors',
'author_sort', 'author_sort_map' 'comments',
'cover_data', 'tags', 'language', 'lpath',
'size', 'thumbnail'])
SC_FIELDS_NOT_COPIED.union(
SC_FIELDS_COPY_NOT_NULL)
SERIALIZABLE_FIELDS = SOCIAL_METADATA_FIELDS.union(
USER_METADATA_FIELDS).union(

View File

@ -9,9 +9,11 @@ import copy
import traceback
from calibre import prints
from calibre.ebooks.metadata.book import COPYABLE_METADATA_FIELDS
from calibre.ebooks.metadata.book import SC_COPYABLE_FIELDS
from calibre.ebooks.metadata.book import SC_FIELDS_COPY_NOT_NULL
from calibre.ebooks.metadata.book import STANDARD_METADATA_FIELDS
from calibre.ebooks.metadata.book import TOP_LEVEL_CLASSIFIERS
from calibre.library.field_metadata import FieldMetadata
from calibre.utils.date import isoformat, format_date
@ -29,6 +31,8 @@ NULL_VALUES = {
'language' : 'und'
}
field_metadata = FieldMetadata()
class Metadata(object):
'''
@ -111,6 +115,31 @@ class Metadata(object):
_data = object.__getattribute__(self, '_data')
return frozenset(_data['user_metadata'].iterkeys())
def get_standard_metadata(self, field, make_copy):
'''
return field metadata from the field if it is there. Otherwise return
None. field is the key name, not the label. Return a copy if requested,
just in case the user wants to change values in the dict.
'''
if field in field_metadata and field_metadata[field]['kind'] == 'field':
if make_copy:
return copy.deepcopy(field_metadata[field])
return field_metadata[field]
return None
def get_all_standard_metadata(self, make_copy):
'''
return a dict containing all the standard field metadata associated with
the book.
'''
if not make_copy:
return field_metadata
res = {}
for k in field_metadata:
if field_metadata[k]['kind'] == 'field':
res[k] = copy.deepcopy(field_metadata[k])
return res
def get_all_user_metadata(self, make_copy):
'''
return a dict containing all the custom field metadata associated with
@ -223,22 +252,23 @@ class Metadata(object):
self.author_sort = other.author_sort
if replace_metadata:
SPECIAL_FIELDS = frozenset(['lpath', 'size', 'comments', 'thumbnail'])
for attr in COPYABLE_METADATA_FIELDS:
# SPECIAL_FIELDS = frozenset(['lpath', 'size', 'comments', 'thumbnail'])
for attr in SC_COPYABLE_FIELDS:
setattr(self, attr, getattr(other, attr, 1.0 if \
attr == 'series_index' else None))
self.tags = other.tags
self.cover_data = getattr(other, 'cover_data',
NULL_VALUES['cover_data'])
NULL_VALUES['cover_data'])
self.set_all_user_metadata(other.get_all_user_metadata(make_copy=True))
for x in SPECIAL_FIELDS:
for x in SC_FIELDS_COPY_NOT_NULL:
copy_not_none(self, other, x)
# language is handled below
else:
for attr in COPYABLE_METADATA_FIELDS:
if hasattr(other, attr):
copy_not_none(self, other, attr)
copy_not_none(self, other, 'thumbnail')
for attr in SC_COPYABLE_FIELDS:
copy_not_none(self, other, attr)
for x in SC_FIELDS_COPY_NOT_NULL:
copy_not_none(self, other, x)
if other.tags:
# Case-insensitive but case preserving merging
lotags = [t.lower() for t in other.tags]
@ -249,6 +279,7 @@ class Metadata(object):
oidx = lotags.index(t)
self.tags[sidx] = other.tags[oidx]
self.tags += [t for t in other.tags if t.lower() in ot-st]
if getattr(other, 'cover_data', False):
other_cover = other.cover_data[-1]
self_cover = self.cover_data[-1] if self.cover_data else ''
@ -256,6 +287,7 @@ class Metadata(object):
if not other_cover: other_cover = ''
if len(other_cover) > len(self_cover):
self.cover_data = other.cover_data
if getattr(other, 'user_metadata_keys', None):
for x in other.user_metadata_keys:
meta = other.get_user_metadata(x, make_copy=True)
@ -274,6 +306,7 @@ class Metadata(object):
self_tags[sidx] = other.tags[oidx]
self_tags += [t for t in other.tags if t.lower() in ot-st]
setattr(self, x, self_tags)
my_comments = getattr(self, 'comments', '')
other_comments = getattr(other, 'comments', '')
if not my_comments:
@ -310,24 +343,49 @@ class Metadata(object):
def format_rating(self):
return unicode(self.rating)
def format_custom_field(self, key):
def format_field(self, key, ignore_series_index=False):
from calibre.ebooks.metadata import authors_to_string
'''
returns the tuple (field_name, formatted_value)
'''
cmeta = self.get_user_metadata(key, make_copy=False)
name = unicode(cmeta['name'])
res = self.get(key, None)
if res is not None:
if key in self.user_metadata_keys:
res = self.get(key, None)
if res is None or res == '':
return (None, None)
cmeta = self.get_user_metadata(key, make_copy=False)
name = unicode(cmeta['name'])
datatype = cmeta['datatype']
if datatype == 'text' and cmeta['is_multiple']:
res = u', '.join(res)
elif datatype == 'series':
res = res + ' [%s]'%self.format_series_index(val=self.get_extra(key))
if not ignore_series_index:
res = res + \
' [%s]'%self.format_series_index(val=self.get_extra(key))
elif datatype == 'datetime':
res = format_date(res, cmeta['display'].get('date_format','dd MMM yyyy'))
elif datatype == 'bool':
res = _('Yes') if res else _('No')
return (name, unicode(res))
return (name, unicode(res))
if key in field_metadata and field_metadata[key]['kind'] == 'field':
res = self.get(key, None)
if res is None or res == '':
return (None, None)
fmeta = field_metadata[key]
name = unicode(fmeta['name'])
datatype = fmeta['datatype']
if key == 'authors':
res = authors_to_string(res)
elif datatype == 'text' and fmeta['is_multiple']:
res = u', '.join(res)
elif datatype == 'series':
if not ignore_series_index:
res = res + ' [%s]'%self.format_series_index()
elif datatype == 'datetime':
res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy'))
return (name, unicode(res))
return (None, None)
def __unicode__(self):
from calibre.ebooks.metadata import authors_to_string
@ -366,7 +424,7 @@ class Metadata(object):
for key in self.user_metadata_keys:
val = self.get(key, None)
if val is not None:
(name, val) = self.format_custom_field(key)
(name, val) = self.format_field(key)
fmt(name, unicode(val))
return u'\n'.join(ans)
@ -391,7 +449,7 @@ class Metadata(object):
for key in self.user_metadata_keys:
val = self.get(key, None)
if val is not None:
(name, val) = self.format_custom_field(key)
(name, val) = self.format_field(key)
ans += [(name, val)]
for i, x in enumerate(ans):
ans[i] = u'<tr><td><b>%s</b></td><td>%s</td></tr>'%x

View File

@ -320,7 +320,7 @@ class BooksModel(QAbstractTableModel): # {{{
(sidx, prepare_string_for_xml(series))
mi = self.db.get_metadata(idx)
for key in mi.user_metadata_keys:
name, val = mi.format_custom_field(key)
name, val = mi.format_field(key)
if val is not None:
data[name] = val
return data

View File

@ -5,6 +5,7 @@ Created on 25 May 2010
'''
from calibre.utils.ordered_dict import OrderedDict
from calibre.utils.config import tweaks
class TagsIcons(dict):
'''
@ -213,7 +214,7 @@ class FieldMetadata(dict):
'datatype':'text',
'is_multiple':None,
'kind':'field',
'name':None,
'name':_('On Device'),
'search_terms':['ondevice'],
'is_custom':False,
'is_category':False}),
@ -231,7 +232,7 @@ class FieldMetadata(dict):
'datatype':'datetime',
'is_multiple':None,
'kind':'field',
'name':None,
'name':_('Published'),
'search_terms':['pubdate'],
'is_custom':False,
'is_category':False}),
@ -258,7 +259,7 @@ class FieldMetadata(dict):
'datatype':'float',
'is_multiple':None,
'kind':'field',
'name':None,
'name':_('Size (MB)'),
'search_terms':['size'],
'is_custom':False,
'is_category':False}),
@ -267,7 +268,7 @@ class FieldMetadata(dict):
'datatype':'datetime',
'is_multiple':None,
'kind':'field',
'name':None,
'name':_('Date'),
'search_terms':['date'],
'is_custom':False,
'is_category':False}),
@ -276,7 +277,7 @@ class FieldMetadata(dict):
'datatype':'text',
'is_multiple':None,
'kind':'field',
'name':None,
'name':_('Title'),
'search_terms':['title'],
'is_custom':False,
'is_category':False}),
@ -310,6 +311,10 @@ class FieldMetadata(dict):
self._tb_cats[k]['display'] = {}
self._tb_cats[k]['is_editable'] = True
self._add_search_terms_to_map(k, v['search_terms'])
self._tb_cats['timestamp']['display'] = {
'date_format': tweaks['gui_timestamp_display_format']}
self._tb_cats['pubdate']['display'] = {
'date_format': tweaks['gui_pubdate_display_format']}
self.custom_field_prefix = '#'
self.get = self._tb_cats.get
@ -410,7 +415,7 @@ class FieldMetadata(dict):
if datatype == 'series':
key += '_index'
self._tb_cats[key] = {'table':None, 'column':None,
'datatype':'float', 'is_multiple':False,
'datatype':'float', 'is_multiple':None,
'kind':'field', 'name':'',
'search_terms':[key], 'label':label+'_index',
'colnum':None, 'display':{},