mirror of
git://github.com/kovidgoyal/calibre.git
synced 2026-05-08 14:14:31 +02:00
Build enough of custom_column metadata support to implement reserved column names.
Fix search to not go pink when the timer expires, and to not be always pink for devices.
This commit is contained in:
parent
44fb01dc3f
commit
beb817b5cb
6 changed files with 104 additions and 28 deletions
90
src/calibre/devices/metadata_serializer.py
Normal file
90
src/calibre/devices/metadata_serializer.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
'''
|
||||
Created on 21 May 2010
|
||||
|
||||
@author: charles
|
||||
'''
|
||||
|
||||
from calibre.constants import filesystem_encoding, preferred_encoding
|
||||
from calibre import isbytestring
|
||||
import json
|
||||
|
||||
class MetadataSerializer(object):
|
||||
|
||||
SERIALIZED_ATTRS = [
|
||||
'lpath', 'title', 'authors', 'mime', 'size', 'tags', 'author_sort',
|
||||
'title_sort', 'comments', 'category', 'publisher', 'series',
|
||||
'series_index', 'rating', 'isbn', 'language', 'application_id',
|
||||
'book_producer', 'lccn', 'lcc', 'ddc', 'rights', 'publication_type',
|
||||
'uuid',
|
||||
]
|
||||
|
||||
def to_json(self):
|
||||
json = {}
|
||||
for attr in self.SERIALIZED_ATTRS:
|
||||
val = getattr(self, attr)
|
||||
if isbytestring(val):
|
||||
enc = filesystem_encoding if attr == 'lpath' else preferred_encoding
|
||||
val = val.decode(enc, 'replace')
|
||||
elif isinstance(val, (list, tuple)):
|
||||
val = [x.decode(preferred_encoding, 'replace') if
|
||||
isbytestring(x) else x for x in val]
|
||||
json[attr] = val
|
||||
return json
|
||||
|
||||
def read_json(self, cache_file):
|
||||
with open(cache_file, 'rb') as f:
|
||||
js = json.load(f, encoding='utf-8')
|
||||
return js
|
||||
|
||||
def write_json(self, js, cache_file):
|
||||
with open(cache_file, 'wb') as f:
|
||||
json.dump(js, f, indent=2, encoding='utf-8')
|
||||
|
||||
def string_to_value(self, string, col_metadata, column_label=None):
|
||||
'''
|
||||
if column_label is none, col_metadata must be a dict containing custom
|
||||
column metadata for one column. If column_label is not none, then
|
||||
col_metadata must be a dict of custom column metadata, with column
|
||||
labels as keys. Metadata for standard columns is always assumed to be in
|
||||
the col_metadata dict. If column_label is not standard and is not in
|
||||
col_metadata, check if it matches a custom column. If so, use that
|
||||
column metadata. See get_column_metadata below.
|
||||
'''
|
||||
pass
|
||||
|
||||
def value_to_display(self, value, col_metadata, column_label=None):
|
||||
pass
|
||||
|
||||
def value_to_string (self, value, col_metadata, column_label=None):
|
||||
pass
|
||||
|
||||
def get_column_metadata(self, column_label = None, from_book=None):
|
||||
'''
|
||||
if column_label is None, then from_book must not be None. Returns the
|
||||
complete set of custom column metadata for that book.
|
||||
|
||||
If column_label is not None, return the column metadata for the given
|
||||
column. This works even if the label is for a built-in column. If
|
||||
from_book is None, then column_label must be a current custom column
|
||||
label or a standard label. If from_book is not None, then the column
|
||||
metadata from that metadata set is returned if it exists, otherwise the
|
||||
standard metadata for that column is returned. If neither is found,
|
||||
return {}
|
||||
'''
|
||||
pass
|
||||
|
||||
def get_custom_column_labels(self, book):
|
||||
'''
|
||||
returns a list of custom column attributes in the book metadata.
|
||||
'''
|
||||
pass
|
||||
|
||||
def get_standard_column_labels(self):
|
||||
'''
|
||||
returns a list of standard attributes that should be in any book's
|
||||
metadata
|
||||
'''
|
||||
pass
|
||||
|
||||
metadata_serializer = MetadataSerializer()
|
||||
|
||||
|
|
@ -9,20 +9,14 @@
|
|||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.devices.mime import mime_type_ext
|
||||
from calibre.devices.interface import BookList as _BookList
|
||||
from calibre.constants import filesystem_encoding, preferred_encoding
|
||||
from calibre.devices.metadata_serializer import MetadataSerializer
|
||||
from calibre.constants import preferred_encoding
|
||||
from calibre import isbytestring
|
||||
|
||||
class Book(MetaInformation):
|
||||
class Book(MetaInformation, MetadataSerializer):
|
||||
|
||||
BOOK_ATTRS = ['lpath', 'size', 'mime', 'device_collections']
|
||||
|
||||
JSON_ATTRS = [
|
||||
'lpath', 'title', 'authors', 'mime', 'size', 'tags', 'author_sort',
|
||||
'title_sort', 'comments', 'category', 'publisher', 'series',
|
||||
'series_index', 'rating', 'isbn', 'language', 'application_id',
|
||||
'book_producer', 'lccn', 'lcc', 'ddc', 'rights', 'publication_type',
|
||||
'uuid',
|
||||
]
|
||||
|
||||
def __init__(self, prefix, lpath, size=None, other=None):
|
||||
from calibre.ebooks.metadata.meta import path_to_ext
|
||||
|
|
@ -82,19 +76,6 @@ def smart_update(self, other):
|
|||
val = getattr(other, attr, None)
|
||||
setattr(self, attr, val)
|
||||
|
||||
def to_json(self):
|
||||
json = {}
|
||||
for attr in self.JSON_ATTRS:
|
||||
val = getattr(self, attr)
|
||||
if isbytestring(val):
|
||||
enc = filesystem_encoding if attr == 'lpath' else preferred_encoding
|
||||
val = val.decode(enc, 'replace')
|
||||
elif isinstance(val, (list, tuple)):
|
||||
val = [x.decode(preferred_encoding, 'replace') if
|
||||
isbytestring(x) else x for x in val]
|
||||
json[attr] = val
|
||||
return json
|
||||
|
||||
class BookList(_BookList):
|
||||
|
||||
def supports_collections(self):
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
from calibre import prints, isbytestring
|
||||
from calibre.constants import filesystem_encoding
|
||||
from calibre.devices.metadata_serializer import metadata_serializer as ms
|
||||
from calibre.devices.usbms.cli import CLI
|
||||
from calibre.devices.usbms.device import Device
|
||||
from calibre.devices.usbms.books import BookList, Book
|
||||
|
|
@ -260,8 +261,7 @@ def write_prefix(prefix, listid):
|
|||
os.makedirs(self.normalize_path(prefix))
|
||||
js = [item.to_json() for item in booklists[listid] if
|
||||
hasattr(item, 'to_json')]
|
||||
with open(self.normalize_path(os.path.join(prefix, self.METADATA_CACHE)), 'wb') as f:
|
||||
json.dump(js, f, indent=2, encoding='utf-8')
|
||||
ms.write_json(js, self.normalize_path(os.path.join(prefix, self.METADATA_CACHE)))
|
||||
write_prefix(self._main_prefix, 0)
|
||||
write_prefix(self._card_a_prefix, 1)
|
||||
write_prefix(self._card_b_prefix, 2)
|
||||
|
|
@ -293,8 +293,7 @@ def parse_metadata_cache(cls, bl, prefix, name):
|
|||
cache_file = cls.normalize_path(os.path.join(prefix, name))
|
||||
if os.access(cache_file, os.R_OK):
|
||||
try:
|
||||
with open(cache_file, 'rb') as f:
|
||||
js = json.load(f, encoding='utf-8')
|
||||
js = ms.read_json(cache_file)
|
||||
for item in js:
|
||||
book = cls.book_class(prefix, item.get('lpath', None))
|
||||
for key in item.keys():
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
from PyQt4.QtCore import SIGNAL
|
||||
from PyQt4.Qt import QDialog, Qt, QListWidgetItem, QVariant
|
||||
|
||||
from calibre.devices.metadata_serializer import metadata_serializer
|
||||
from calibre.gui2.dialogs.config.create_custom_column_ui import Ui_QCreateCustomColumn
|
||||
from calibre.gui2 import error_dialog
|
||||
|
||||
|
|
@ -102,6 +103,8 @@ def accept(self):
|
|||
return self.simple_error('', _('No lookup name was provided'))
|
||||
if not col_heading:
|
||||
return self.simple_error('', _('No column heading was provided'))
|
||||
if col in metadata_serializer.SERIALIZED_ATTRS:
|
||||
return self.simple_error('', _('The lookup name %s is reserved and cannot be used')%col)
|
||||
bad_col = False
|
||||
if col in self.parent.custcols:
|
||||
if not self.editing_col or self.parent.custcols[col]['num'] != self.orig_column_number:
|
||||
|
|
|
|||
|
|
@ -883,7 +883,7 @@ def search(self, text, refinement, reset=True):
|
|||
self.reset()
|
||||
self.last_search = text
|
||||
if self.last_search:
|
||||
self.searched.emit(False)
|
||||
self.searched.emit(True)
|
||||
|
||||
|
||||
def sort(self, col, order, reset=True):
|
||||
|
|
|
|||
|
|
@ -136,12 +136,12 @@ def mouse_released(self, event):
|
|||
def text_edited_slot(self, text):
|
||||
if self.as_you_type:
|
||||
text = unicode(text)
|
||||
self.prev_text = text
|
||||
self.timer = self.startTimer(self.__class__.INTERVAL)
|
||||
|
||||
def timerEvent(self, event):
|
||||
self.killTimer(event.timerId())
|
||||
if event.timerId() == self.timer:
|
||||
self.timer = None
|
||||
self.do_search()
|
||||
|
||||
@property
|
||||
|
|
@ -190,6 +190,9 @@ def search_from_tags(self, tags, all):
|
|||
def set_search_string(self, txt):
|
||||
self.normalize_state()
|
||||
self.setEditText(txt)
|
||||
if self.timer is not None: # Turn off any timers that got started in setEditText
|
||||
self.killTimer(self.timer)
|
||||
self.timer = None
|
||||
self.search.emit(txt, False)
|
||||
self.line_edit.end(False)
|
||||
self.initial_state = False
|
||||
|
|
|
|||
Loading…
Reference in a new issue