Merge from trunk

This commit is contained in:
Charles Haley 2010-09-24 16:58:04 +01:00
commit ce1f323df5
5 changed files with 53 additions and 36 deletions

View File

@ -956,10 +956,10 @@ class DeviceBooksModel(BooksModel): # {{{
if index.isValid():
cname = self.column_map[index.column()]
if cname in self.editable and \
cname != 'collections' or \
(cname != 'collections' or \
(callable(getattr(self.db, 'supports_collections', None)) and \
self.db.supports_collections() and \
prefs['manage_device_metadata']=='manual'):
prefs['manage_device_metadata']=='manual')):
flags |= Qt.ItemIsEditable
return flags

View File

@ -36,14 +36,14 @@ class MetadataBackup(Thread): # {{{
def run(self):
while self.keep_running:
try:
id_ = self.db.dirtied_queue.get(True, 5)
id_ = self.db.dirtied_queue.get()
except Empty:
continue
except:
# Happens during interpreter shutdown
break
if self.dump_func([id_]) is None:
# An exception occured in dump_func, retry once
# An exception occurred in dump_func, retry once
prints('Failed to backup metadata for id:', id_, 'once')
time.sleep(2)
if not self.dump_func([id_]):
@ -84,9 +84,12 @@ class CoverCache(Thread): # {{{
def run(self):
while self.keep_running:
try:
id_ = self.load_queue.get(True, 1)
id_ = self.load_queue.get()
except Empty:
continue
except:
#Happens during interpreter shutdown
break
try:
img = self._image_for_id(id_)
except:

View File

@ -32,8 +32,9 @@ def send_message(msg=''):
t.conn.send('refreshdb:'+msg)
t.conn.close()
def write_dirtied(db):
prints('Backing up metadata')
db.dump_metadata()
def get_parser(usage):
parser = OptionParser(usage)
@ -259,6 +260,7 @@ def do_add(db, paths, one_book_per_directory, recurse, add_duplicates):
print >>sys.stderr, '\t', title+':'
print >>sys.stderr, '\t\t ', path
write_dirtied(db)
send_message()
finally:
sys.stdout = orig
@ -299,6 +301,7 @@ def do_add_empty(db, title, authors, isbn):
if isbn:
mi.isbn = isbn
db.import_book(mi, [])
write_dirtied()
send_message()
def command_add(args, dbpath):
@ -452,6 +455,7 @@ def do_set_metadata(db, id, stream):
db.set_metadata(id, mi)
db.clean()
do_show_metadata(db, id, False)
write_dirtied()
send_message()
def set_metadata_option_parser():

View File

@ -563,7 +563,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
def metadata_for_field(self, key):
return self.field_metadata[key]
def dump_metadata(self, book_ids, remove_from_dirtied=True, commit=True):
def dump_metadata(self, book_ids=None, remove_from_dirtied=True, commit=True):
'Write metadata for each record to an individual OPF file'
if book_ids is None:
book_ids = [x[0] for x in self.conn.get(
'SELECT book FROM metadata_dirtied', all=True)]
for book_id in book_ids:
if not self.data.has_id(book_id):
continue
@ -584,13 +588,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
return True
def dirtied(self, book_ids, commit=True):
self.conn.executemany(
'INSERT OR REPLACE INTO metadata_dirtied (book) VALUES (?)',
[(x,) for x in book_ids])
for book in book_ids:
try:
self.conn.execute(
'INSERT INTO metadata_dirtied (book) VALUES (?)',
(book,))
self.dirtied_queue.put(book)
except IntegrityError:
# Already in table
continue
if commit:
self.conn.commit()
for x in book_ids:
self.dirtied_queue.put(x)
def get_metadata(self, idx, index_is_id=False, get_cover=False):
'''

View File

@ -46,29 +46,29 @@ You can do more than just simple substitution with the templates. You can also c
First, conditionally including text. There are cases where you might want to have text appear in the output only if a field is not empty. A common case is series and series_index, where you want either nothing or the two values with a hyphen between them. Calibre handles this case using a special field syntax.
For example, assume you want to use the template
For example, assume you want to use the template::
{series} - {series_index} - {title}
If the book has no series, the answer will be '- - title'. Many people would rather the result be simply 'title', without the hyphens. To do this, use the extended syntax `{field:|prefix_text|suffix_text}`. When you use this syntax, if field has the value SERIES then the result will be prefix_textSERIESsuffix_text. If field has no value, then the result will be the empty string (nothing). The prefix and suffix can contain blanks.
If the book has no series, the answer will be '- - title'. Many people would rather the result be simply 'title', without the hyphens. To do this, use the extended syntax ``{field:|prefix_text|suffix_text}``. When you use this syntax, if field has the value SERIES then the result will be prefix_textSERIESsuffix_text. If field has no value, then the result will be the empty string (nothing). The prefix and suffix can contain blanks.
Using this syntax, we can solve the above series problem with the template:
Using this syntax, we can solve the above series problem with the template::
{series}{series_index:| - | - }{title}
The hyphens will be included only if the book has a series index.
Notes: you must include the : character if you want to use a prefix or a suffix. You must either use no | characters or both of them; using one, as in `{field:| - }`, is not allowed. It is OK not to provide any text for one side or the other, such as in `{series:|| - }`. Using `{title:||}` is the same as using `{title}`.
Notes: you must include the : character if you want to use a prefix or a suffix. You must either use no \| characters or both of them; using one, as in ``{field:| - }``, is not allowed. It is OK not to provide any text for one side or the other, such as in ``{series:|| - }``. Using ``{title:||}`` is the same as using ``{title}``.
Second: formatting. Suppose you wanted to ensure that the series_index is always formatted as three digits with leading zeros. This would do the trick::
{series_index:0>3s} - Three digits with leading zeros
If instead of leading zeros you want leading spaces, use:
If instead of leading zeros you want leading spaces, use::
{series_index:>3s} - Three digits with leading spaces
For trailing zeros, use:
For trailing zeros, use::
{series_index:0<3s} - Three digits with trailing zeros
@ -85,7 +85,7 @@ Advanced features
Using templates in custom columns
----------------------------------
There are sometimes cases where you want to display metadata that |app| does not normally display, or to display data in a way different from how |app| normally does. For example, you might want to display the ISBN, a field that |app| does not display. You can use custom columns for this. To do so, you create a column with the type 'column built from other columns' (hereafter called composite columns), enter a template, and |app| will display in the column the result of evaluating that template. To display the isbn, create the column and enter `{isbn}` into the template box. To display a column containing the values of two series custom columns separated by a comma, use `{#series1:||,}{#series2}`.
There are sometimes cases where you want to display metadata that |app| does not normally display, or to display data in a way different from how |app| normally does. For example, you might want to display the ISBN, a field that |app| does not display. You can use custom columns for this. To do so, you create a column with the type 'column built from other columns' (hereafter called composite columns), enter a template, and |app| will display in the column the result of evaluating that template. To display the isbn, create the column and enter ``{isbn}`` into the template box. To display a column containing the values of two series custom columns separated by a comma, use ``{#series1:||,}{#series2}``.
Composite columns can use any template option, including formatting.
@ -94,30 +94,30 @@ You cannot change the data contained in a composite column. If you edit a compos
Using functions in templates
-----------------------------
Suppose you want to display the value of a field in upper case, when that field is normally in title case. You can do this (and many more things) using the functions available for templates. For example, to display the title in upper case, use `{title:uppercase()}`. To display it in title case, use `{title:titlecase()}`.
Suppose you want to display the value of a field in upper case, when that field is normally in title case. You can do this (and many more things) using the functions available for templates. For example, to display the title in upper case, use ``{title:uppercase()}``. To display it in title case, use ``{title:titlecase()}``.
Function references replace the formatting specification, going after the : and before the first `|` or the closing `}`. Functions must always end with `()`. Some functions take extra values (arguments), and these go inside the `()`.
Function references replace the formatting specification, going after the : and before the first ``|`` or the closing ``}``. Functions must always end with ``()``. Some functions take extra values (arguments), and these go inside the ``()``.
The syntax for using functions is `{field:function(arguments)}`, or `{field:function(arguments)|prefix|suffix}`. Argument values cannot contain a comma, because it is used to separate arguments. Functions return the value of the field used in the template, suitably modified.
The syntax for using functions is ``{field:function(arguments)}``, or ``{field:function(arguments)|prefix|suffix}``. Argument values cannot contain a comma, because it is used to separate arguments. Functions return the value of the field used in the template, suitably modified.
The functions available are:
* `lowercase()` -- return value of the field in lower case.
* `uppercase()` -- return the value of the field in upper case.
* `titlecase()` -- return the value of the field in title case.
* `capitalize()` -- return the value as capitalized.
* `ifempty(text)` -- if the field is not empty, return the value of the field. Otherwise return `text`.
* `test(text if not empty, text if empty)` -- return `text if not empty` if the field is not empty, otherwise return `text if empty`.
* `shorten(left chars, middle text, right chars)` -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use `{title:shorten(9,-,5)}, the result will be `Ancient E-nhoe`. If the field's length is less than `left chars` + `right chars` + the length of `middle text`, then the field will be used intact. For example, the title `The Dome` would not be changed.
* `lookup(field if not empty, field if empty)` -- like test, except the arguments are field (metadata) names, not text. The value of the appropriate field will be fetched and used. Note that because composite columns are fields, you can use this function in one composite field to use the value of some other composite field. This is extremely useful when constructing variable save paths (more later).
* `re(pattern, replacement)` -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of |app|, these are python-compatible regular expressions.
* ``lowercase()`` -- return value of the field in lower case.
* ``uppercase()`` -- return the value of the field in upper case.
* ``titlecase()`` -- return the value of the field in title case.
* ``capitalize()`` -- return the value as capitalized.
* ``ifempty(text)`` -- if the field is not empty, return the value of the field. Otherwise return `text`.
* ``test(text if not empty, text if empty)`` -- return `text if not empty` if the field is not empty, otherwise return `text if empty`.
* ``shorten(left chars, middle text, right chars)`` -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use ``{title:shorten(9,-,5)}``, the result will be `Ancient E-nhoe`. If the field's length is less than ``left chars`` + ``right chars`` + the length of ``middle text``, then the field will be used intact. For example, the title `The Dome` would not be changed.
* ``lookup(field if not empty, field if empty)`` -- like test, except the arguments are field (metadata) names, not text. The value of the appropriate field will be fetched and used. Note that because composite columns are fields, you can use this function in one composite field to use the value of some other composite field. This is extremely useful when constructing variable save paths (more later).
* ``re(pattern, replacement)`` -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of |app|, these are python-compatible regular expressions.
Special notes for save/send templates
-------------------------------------
Special processing is applied when a template is used in a `save to disk` or `send to device` template. The values of the fields are cleaned, replacing characters that are special to file systems with underscores, including slashes. This means that field text cannot be used to create folders. However, slashes are not changed in prefix or suffix strings, so slashes in these strings will cause folders to be created. Because of this, you can create variable-depth folder structure.
For example, assume we want the folder structure `series/series_index - title`, with the caveat that if series does not exist, then the title should be in the top folder. The template to do this is
For example, assume we want the folder structure `series/series_index - title`, with the caveat that if series does not exist, then the title should be in the top folder. The template to do this is::
{series:||/}{series_index:|| - }{title}
@ -126,6 +126,8 @@ The slash and the hyphen appear only if series is not empty.
The lookup function lets us do even fancier processing. For example, assume we want the following: if a book has a series, then we want the folder structure `series/series index - title.fmt`. If the book does not have a series, then we want the folder structure `genre/author_sort/title.fmt`. If the book has no genre, use 'Unknown'. We want two completely different paths, depending on the value of series.
To accomplish this, we:
1. Create a composite field (call it AA) containing `{series:||}/{series_index} - {title'}`. If the series is not empty, then this template will produce `series/series_index - title`.
2. Create a composite field (call it BB) containing `{#genre:ifempty(Unknown)}/{author_sort}/{title}`. This template produces `genre/author_sort/title`, where an empty genre is replaced wuth `Unknown`.
3. Set the save template to `{series:lookup(AA,BB)}`. This template chooses composite field AA if series is not empty, and composite field BB if series is empty. We therefore have two completely different save paths, depending on whether or not `series` is empty.
1. Create a composite field (call it AA) containing ``{series:||}/{series_index} - {title'}``. If the series is not empty, then this template will produce `series/series_index - title`.
2. Create a composite field (call it BB) containing ``{#genre:ifempty(Unknown)}/{author_sort}/{title}``. This template produces `genre/author_sort/title`, where an empty genre is replaced wuth `Unknown`.
3. Set the save template to ``{series:lookup(AA,BB)}``. This template chooses composite field AA if series is not empty, and composite field BB if series is empty. We therefore have two completely different save paths, depending on whether or not `series` is empty.