Added all standard fields to the metadata dictionary. The datatypes might be wrong in some cases.

This commit is contained in:
Charles Haley 2010-05-26 16:35:41 +01:00
parent 3d38872b56
commit a124d9c799
6 changed files with 285 additions and 216 deletions

View File

@ -14,7 +14,7 @@ from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \
QAbstractItemModel, QVariant, QModelIndex
from calibre.gui2 import config, NONE
from calibre.utils.config import prefs
from calibre.library.tag_categories import TagsIcons
from calibre.library.field_metadata import TagsIcons
class TagsView(QTreeView): # {{{

View File

@ -17,7 +17,7 @@ from calibre.utils.config import tweaks
from calibre.utils.date import parse_date, now, UNDEFINED_DATE
from calibre.utils.search_query_parser import SearchQueryParser
from calibre.utils.pyparsing import ParseException
from calibre.library.tag_categories import TagsMetadata
# from calibre.library.field_metadata import FieldMetadata
class CoverCache(QThread):
@ -387,9 +387,9 @@ class ResultCache(SearchQueryParser):
# get the db columns for the standard searchables
for x in self.tag_browser_categories:
if (len(self.tag_browser_categories[x]['search_labels']) and \
self.tag_browser_categories[x]['kind'] in ['standard', 'not_cat']):
MAP[x] = self.FIELD_MAP[self.tag_browser_categories.get_field_label(x)]
if len(self.tag_browser_categories[x]['search_labels']) and \
not self.tag_browser_categories.is_custom_field(x):
MAP[x] = self.tag_browser_categories[x]['rec_index']
if self.tag_browser_categories[x]['datatype'] != 'text':
EXCLUDE_FIELDS.append(MAP[x])

View File

@ -144,11 +144,14 @@ class CustomColumns(object):
for k in sorted(self.custom_column_label_map.keys()):
v = self.custom_column_label_map[k]
if v['normalized']:
searchable = True
else:
searchable = False
tn = 'custom_column_{0}'.format(v['num'])
self.tag_browser_categories.add_custom_field(
field_name = v['label'], table = tn, column='value',
datatype=v['datatype'], is_multiple=v['is_multiple'],
number=v['num'], name=v['name'])
self.tag_browser_categories.add_custom_field(label=v['label'],
table=tn, column='value', datatype=v['datatype'],
is_multiple=v['is_multiple'], colnum=v['num'],
name=v['name'], searchable=searchable)
def get_custom(self, idx, label=None, num=None, index_is_id=False):
if label is not None:

View File

@ -20,7 +20,7 @@ from PyQt4.QtGui import QImage
from calibre.ebooks.metadata import title_sort
from calibre.library.database import LibraryDatabase
from calibre.library.tag_categories import TagsMetadata, TagsIcons
from calibre.library.field_metadata import FieldMetadata, TagsIcons
from calibre.library.schema_upgrades import SchemaUpgrade
from calibre.library.caches import ResultCache
from calibre.library.custom_columns import CustomColumns
@ -116,7 +116,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.books_list_filter = self.conn.create_dynamic_filter('books_list_filter')
def __init__(self, library_path, row_factory=False):
self.tag_browser_categories = TagsMetadata() #.get_tag_browser_categories()
self.tag_browser_categories = FieldMetadata() #.get_tag_browser_categories()
if not os.path.exists(library_path):
os.makedirs(library_path)
self.listeners = set([])
@ -204,12 +204,21 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
'sort':11, 'author_sort':12, 'formats':13, 'isbn':14, 'path':15,
'lccn':16, 'pubdate':17, 'flags':18, 'uuid':19}
for k,v in self.FIELD_MAP.iteritems():
self.tag_browser_categories.set_field_record_index(k, v, prefer_custom=False)
base = max(self.FIELD_MAP.values())
for col in custom_cols:
self.FIELD_MAP[col] = base = base+1
self.tag_browser_categories.set_field_record_index(
self.custom_column_num_map[col]['label'],
base,
prefer_custom=True)
self.FIELD_MAP['cover'] = base+1
self.tag_browser_categories.set_field_record_index('cover', base+1, prefer_custom=False)
self.FIELD_MAP['ondevice'] = base+2
self.tag_browser_categories.set_field_record_index('ondevice', base+2, prefer_custom=False)
script = '''
DROP VIEW IF EXISTS meta2;
@ -672,10 +681,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
icon, tooltip = None, ''
label = tb_cats.get_field_label(category)
if icon_map:
if cat['kind'] == 'standard':
if not tb_cats.is_custom_field(category):
if category in icon_map:
icon = icon_map[label]
elif cat['kind'] == 'custom':
else:
icon = icon_map[':custom']
icon_map[category] = icon
tooltip = self.custom_column_label_map[label]['name']

View File

@ -0,0 +1,259 @@
'''
Created on 25 May 2010
@author: charles
'''
from UserDict import DictMixin
from calibre.utils.ordered_dict import OrderedDict
class TagsIcons(dict):
'''
If the client wants icons to be in the tag structure, this class must be
instantiated and filled in with real icons. If this class is instantiated
and passed to get_categories, All items must be given a value not None
'''
category_icons = ['authors', 'series', 'formats', 'publisher', 'rating',
'news', 'tags', ':custom', ':user', 'search',]
def __init__(self, icon_dict):
for a in self.category_icons:
if a not in icon_dict:
raise ValueError('Missing category icon [%s]'%a)
self[a] = icon_dict[a]
class FieldMetadata(dict, DictMixin):
# kind == standard: is tag category. May be a search label. Is db col
# or is specially handled (e.g., news)
# kind == not_cat: Is not a tag category. May be a search label. Is db col
# kind == user: user-defined tag category
# kind == search: saved-searches category
# For 'standard', the order below is the order that the categories will
# appear in the tags pane.
#
# label is the column label. key is either the label or in the case of
# custom fields, the label prefixed with 'x'. Because of the prefixing,
# there cannot be a name clash between standard and custom fields, so key
# can be used as the metadata dictionary key.
category_items_ = [
('authors', {'table':'authors', 'column':'name',
'datatype':'text', 'is_multiple':False,
'kind':'standard', 'name':_('Authors'),
'search_labels':['authors', 'author'],
'is_custom':False}),
('series', {'table':'series', 'column':'name',
'datatype':'text', 'is_multiple':False,
'kind':'standard', 'name':_('Series'),
'search_labels':['series'],
'is_custom':False}),
('formats', {'table':None, 'column':None,
'datatype':'text', 'is_multiple':False, # must think what type this is!
'kind':'standard', 'name':_('Formats'),
'search_labels':['formats', 'format'],
'is_custom':False}),
('publisher', {'table':'publishers', 'column':'name',
'datatype':'text', 'is_multiple':False,
'kind':'standard', 'name':_('Publishers'),
'search_labels':['publisher'],
'is_custom':False}),
('rating', {'table':'ratings', 'column':'rating',
'datatype':'rating', 'is_multiple':False,
'kind':'standard', 'name':_('Ratings'),
'search_labels':['rating'],
'is_custom':False}),
('news', {'table':'news', 'column':'name',
'datatype':None, 'is_multiple':False,
'kind':'standard', 'name':_('News'),
'search_labels':[],
'is_custom':False}),
('tags', {'table':'tags', 'column':'name',
'datatype':'text', 'is_multiple':True,
'kind':'standard', 'name':_('Tags'),
'search_labels':['tags', 'tag'],
'is_custom':False}),
('author_sort',{'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('comments', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':['comments', 'comment'], 'is_custom':False}),
('cover', {'table':None, 'column':None, 'datatype':None,
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':['cover'], 'is_custom':False}),
('flags', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('id', {'table':None, 'column':None, 'datatype':'int',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('isbn', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':['isbn'], 'is_custom':False}),
('lccn', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('ondevice', {'table':None, 'column':None, 'datatype':'bool',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('path', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('pubdate', {'table':None, 'column':None, 'datatype':'datetime',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':['pubdate'], 'is_custom':False}),
('series_index',{'table':None, 'column':None, 'datatype':'float',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('sort', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('size', {'table':None, 'column':None, 'datatype':'float',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
('timestamp', {'table':None, 'column':None, 'datatype':'datetime',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':['date'], 'is_custom':False}),
('title', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':['title'], 'is_custom':False}),
('uuid', {'table':None, 'column':None, 'datatype':'text',
'is_multiple':False, 'kind':'not_cat', 'name':None,
'search_labels':[], 'is_custom':False}),
]
# search labels that are not db columns
search_items = [ 'all',
# 'date',
'search',
]
def __init__(self):
self._tb_cats = OrderedDict()
for k,v in self.category_items_:
self._tb_cats[k] = v
self._custom_fields = []
self.custom_field_prefix = '#'
def __getitem__(self, key):
return self._tb_cats[key]
def __setitem__(self, key, val):
raise AttributeError('Assigning to this object is forbidden')
def __delitem__(self, key):
del self._tb_cats[key]
def __iter__(self):
for key in self._tb_cats:
yield key
def keys(self):
return self._tb_cats.keys()
def iterkeys(self):
for key in self._tb_cats:
yield key
def iteritems(self):
for key in self._tb_cats:
yield (key, self._tb_cats[key])
def is_custom_field(self, key):
return key.startswith(self.custom_field_prefix) or key in self._custom_fields
def get_field_label(self, key):
if 'label' not in self._tb_cats[key]:
return key
return self._tb_cats[key]['label']
def get_search_label(self, label):
if 'label' in self._tb_cats:
return label
if self.is_custom_field(label):
return self.custom_field_prefix+label
raise ValueError('Unknown key [%s]'%(label))
def get_custom_fields(self):
return [l for l in self._tb_cats if self._tb_cats[l]['is_custom']]
def add_custom_field(self, label, table, column, datatype,
is_multiple, colnum, name, searchable):
fn = self.custom_field_prefix + label
if fn in self._tb_cats:
raise ValueError('Duplicate custom field [%s]'%(label))
self._custom_fields.append(label)
if searchable:
sl = [fn]
kind = 'standard'
else:
sl = []
kind = 'not_cat'
self._tb_cats[fn] = {'table':table, 'column':column,
'datatype':datatype, 'is_multiple':is_multiple,
'kind':kind, 'name':name,
'search_labels':sl, 'label':label,
'colnum':colnum, 'is_custom':True}
def set_field_record_index(self, label, index, prefer_custom=False):
if prefer_custom:
key = self.custom_field_prefix+label
if key not in self._tb_cats:
key = label
else:
if label in self._tb_cats:
key = label
else:
key = self.custom_field_prefix+label
self._tb_cats[key]['rec_index'] = index # let the exception fly ...
def add_user_category(self, label, name):
if label in self._tb_cats:
raise ValueError('Duplicate user field [%s]'%(label))
self._tb_cats[label] = {'table':None, 'column':None,
'datatype':None, 'is_multiple':False,
'kind':'user', 'name':name,
'search_labels':[], 'is_custom':False}
def add_search_category(self, label, name):
if label in self._tb_cats:
raise ValueError('Duplicate user field [%s]'%(label))
self._tb_cats[label] = {'table':None, 'column':None,
'datatype':None, 'is_multiple':False,
'kind':'search', 'name':name,
'search_labels':[], 'is_custom':False}
# DEFAULT_LOCATIONS = frozenset([
# 'all',
# 'author', # compatibility
# 'authors',
# 'comment', # compatibility
# 'comments',
# 'cover',
# 'date',
# 'format', # compatibility
# 'formats',
# 'isbn',
# 'ondevice',
# 'pubdate',
# 'publisher',
# 'search',
# 'series',
# 'rating',
# 'tag', # compatibility
# 'tags',
# 'title',
# ])
def get_search_labels(self):
s_labels = []
for v in self._tb_cats.itervalues():
map((lambda x:s_labels.append(x)), v['search_labels'])
for v in self.search_items:
s_labels.append(v)
# if set(s_labels) != self.DEFAULT_LOCATIONS:
# print 'search labels and default_locations do not match:'
# print set(s_labels) ^ self.DEFAULT_LOCATIONS
return s_labels

View File

@ -1,202 +0,0 @@
'''
Created on 25 May 2010
@author: charles
'''
from UserDict import DictMixin
from calibre.utils.ordered_dict import OrderedDict
class TagsIcons(dict):
'''
If the client wants icons to be in the tag structure, this class must be
instantiated and filled in with real icons. If this class is instantiated
and passed to get_categories, All items must be given a value not None
'''
category_icons = ['authors', 'series', 'formats', 'publisher', 'rating',
'news', 'tags', ':custom', ':user', 'search',]
def __init__(self, icon_dict):
for a in self.category_icons:
if a not in icon_dict:
raise ValueError('Missing category icon [%s]'%a)
self[a] = icon_dict[a]
class TagsMetadata(dict, DictMixin):
# kind == standard: is tag category. May be a search label. Is db col
# or is specially handled (e.g., news)
# kind == not_cat: Is not a tag category. Should be a search label. Is db col
# kind == user: user-defined tag category
# kind == search: saved-searches category
# Order as has been customary in the tags pane.
category_items_ = [
('authors', {'table':'authors', 'column':'name',
'datatype':'text', 'is_multiple':False,
'kind':'standard', 'name':_('Authors'),
'search_labels':['authors', 'author']}),
('series', {'table':'series', 'column':'name',
'datatype':'text', 'is_multiple':False,
'kind':'standard', 'name':_('Series'),
'search_labels':['series']}),
('formats', {'table':None, 'column':None,
'datatype':None, 'is_multiple':False,
'kind':'standard', 'name':_('Formats'),
'search_labels':['formats', 'format']}),
('publisher', {'table':'publishers', 'column':'name',
'datatype':'text', 'is_multiple':False,
'kind':'standard', 'name':_('Publishers'),
'search_labels':['publisher']}),
('rating', {'table':'ratings', 'column':'rating',
'datatype':'rating', 'is_multiple':False,
'kind':'standard', 'name':_('Ratings'),
'search_labels':['rating']}),
('news', {'table':'news', 'column':'name',
'datatype':None, 'is_multiple':False,
'kind':'standard', 'name':_('News'),
'search_labels':[]}),
('tags', {'table':'tags', 'column':'name',
'datatype':'text', 'is_multiple':True,
'kind':'standard', 'name':_('Tags'),
'search_labels':['tags', 'tag']}),
('comments', {'table':None, 'column':None,
'datatype':'text', 'is_multiple':False,
'kind':'not_cat', 'name':None,
'search_labels':['comments', 'comment']}),
('cover', {'table':None, 'column':None,
'datatype':None, 'is_multiple':False,
'kind':'not_cat', 'name':None,
'search_labels':['cover']}),
('timestamp', {'table':None, 'column':None,
'datatype':'datetime', 'is_multiple':False,
'kind':'not_cat', 'name':None,
'search_labels':['date']}),
('isbn', {'table':None, 'column':None,
'datatype':'text', 'is_multiple':False,
'kind':'not_cat', 'name':None,
'search_labels':['isbn']}),
('pubdate', {'table':None, 'column':None,
'datatype':'datetime', 'is_multiple':False,
'kind':'not_cat', 'name':None,
'search_labels':['pubdate']}),
('title', {'table':None, 'column':None,
'datatype':'text', 'is_multiple':False,
'kind':'not_cat', 'name':None,
'search_labels':['title']}),
]
# search labels that are not db columns
search_items = [ 'all',
# 'date',
'search',
]
def __init__(self):
self._tb_cats = OrderedDict()
for k,v in self.category_items_:
self._tb_cats[k] = v
self._custom_fields = []
self.custom_field_prefix = '#'
def __getitem__(self, key):
return self._tb_cats[key]
def __setitem__(self, key, val):
raise AttributeError('Assigning to this object is forbidden')
def __delitem__(self, key):
del self._tb_cats[key]
def __iter__(self):
for key in self._tb_cats:
yield key
def keys(self):
return self._tb_cats.keys()
def iterkeys(self):
for key in self._tb_cats:
yield key
def iteritems(self):
for key in self._tb_cats:
yield (key, self._tb_cats[key])
def is_custom_field(self, label):
return label.startswith(self.custom_field_prefix) or label in self._custom_fields
def get_field_label(self, key):
if 'label' not in self._tb_cats[key]:
return key
return self._tb_cats[key]['label']
def get_search_label(self, key):
if 'label' in self._tb_cats:
return key
if self.is_custom_field(key):
return self.custom_field_prefix+key
raise ValueError('Unknown key [%s]'%(key))
def get_custom_fields(self):
return [l for l in self._tb_cats if self._tb_cats[l]['kind'] == 'custom']
def add_custom_field(self, field_name, table, column, datatype, is_multiple, number, name):
fn = self.custom_field_prefix + field_name
if fn in self._tb_cats:
raise ValueError('Duplicate custom field [%s]'%(field_name))
self._custom_fields.append(field_name)
self._tb_cats[fn] = {'table':table, 'column':column,
'datatype':datatype, 'is_multiple':is_multiple,
'kind':'custom', 'name':name,
'search_labels':[fn],'label':field_name,
'colnum':number}
def add_user_category(self, field_name, name):
if field_name in self._tb_cats:
raise ValueError('Duplicate user field [%s]'%(field_name))
self._tb_cats[field_name] = {'table':None, 'column':None,
'datatype':None, 'is_multiple':False,
'kind':'user', 'name':name,
'search_labels':[]}
def add_search_category(self, field_name, name):
if field_name in self._tb_cats:
raise ValueError('Duplicate user field [%s]'%(field_name))
self._tb_cats[field_name] = {'table':None, 'column':None,
'datatype':None, 'is_multiple':False,
'kind':'search', 'name':name,
'search_labels':[]}
# DEFAULT_LOCATIONS = frozenset([
# 'all',
# 'author', # compatibility
# 'authors',
# 'comment', # compatibility
# 'comments',
# 'cover',
# 'date',
# 'format', # compatibility
# 'formats',
# 'isbn',
# 'ondevice',
# 'pubdate',
# 'publisher',
# 'search',
# 'series',
# 'rating',
# 'tag', # compatibility
# 'tags',
# 'title',
# ])
def get_search_labels(self):
s_labels = []
for v in self._tb_cats.itervalues():
map((lambda x:s_labels.append(x)), v['search_labels'])
for v in self.search_items:
s_labels.append(v)
# if set(s_labels) != self.DEFAULT_LOCATIONS:
# print 'search labels and default_locations do not match:'
# print set(s_labels) ^ self.DEFAULT_LOCATIONS
return s_labels