Several changes:

1) Add an option to specify the time format when sending to device. This is the analog of the same option that already exists for save to disk.
2) refactor the format_field code. Remove the special parameters on format_field. Add format_field_extended that returns a 4-element tuple (name, formatted val, original val, field metadata).
3) change (simplify) usbms collections management to use new format_field_extended method.
4) change device.py to not call sync_booklists twice.
5) add the fix for gui-not-updating, in hopes that we can avoid merge conflicts
This commit is contained in:
Charles Haley 2010-09-16 14:02:49 +01:00
parent 5602372270
commit e1dd08acef
8 changed files with 68 additions and 41 deletions

View File

@ -94,12 +94,12 @@ class CollectionsBookList(BookList):
def supports_collections(self): def supports_collections(self):
return True return True
def compute_category_name(self, attr, category, cust_field_meta): def compute_category_name(self, attr, category, field_meta):
renames = tweaks['sony_collection_renaming_rules'] renames = tweaks['sony_collection_renaming_rules']
attr_name = renames.get(attr, None) attr_name = renames.get(attr, None)
if attr_name is None: if attr_name is None:
if attr in cust_field_meta: if field_meta['is_custom']:
attr_name = '(%s)'%cust_field_meta[attr]['name'] attr_name = '(%s)'%field_meta['name']
else: else:
attr_name = '' attr_name = ''
elif attr_name != '': elif attr_name != '':
@ -138,23 +138,23 @@ class CollectionsBookList(BookList):
# specified 'on_connect' # specified 'on_connect'
attrs = collection_attributes attrs = collection_attributes
meta_vals = book.get_all_non_none_attributes() meta_vals = book.get_all_non_none_attributes()
cust_field_meta = book.get_all_user_metadata(make_copy=False)
for attr in attrs: for attr in attrs:
attr = attr.strip() attr = attr.strip()
ign, val = book.format_field(attr, ign, val, orig_val, fm = book.format_field_extended(attr)
ignore_series_index=True,
return_multiples_as_list=True)
if not val: continue if not val: continue
if isbytestring(val): if isbytestring(val):
val = val.decode(preferred_encoding, 'replace') val = val.decode(preferred_encoding, 'replace')
if isinstance(val, (list, tuple)): if isinstance(val, (list, tuple)):
val = list(val) val = list(val)
elif fm['datatype'] == 'series':
val = [orig_val]
elif fm['datatype'] == 'text' and fm['is_multiple']:
val = orig_val
else: else:
val = [val] val = [val]
for category in val: for category in val:
is_series = False is_series = False
if attr in cust_field_meta: # is a custom field if fm['is_custom']: # is a custom field
fm = cust_field_meta[attr]
if fm['datatype'] == 'text' and len(category) > 1 and \ if fm['datatype'] == 'text' and len(category) > 1 and \
category[0] == '[' and category[-1] == ']': category[0] == '[' and category[-1] == ']':
continue continue
@ -168,8 +168,7 @@ class CollectionsBookList(BookList):
('series' in collection_attributes and ('series' in collection_attributes and
meta_vals.get('series', None) == category): meta_vals.get('series', None) == category):
is_series = True is_series = True
cat_name = self.compute_category_name(attr, category, cat_name = self.compute_category_name(attr, category, fm)
cust_field_meta)
if cat_name not in collections: if cat_name not in collections:
collections[cat_name] = [] collections[cat_name] = []
collections_lpaths[cat_name] = set() collections_lpaths[cat_name] = set()

View File

@ -829,12 +829,14 @@ class Device(DeviceConfig, DevicePlugin):
ext = os.path.splitext(fname)[1] ext = os.path.splitext(fname)[1]
from calibre.library.save_to_disk import get_components from calibre.library.save_to_disk import get_components
from calibre.library.save_to_disk import config
opts = config().parse()
if not isinstance(template, unicode): if not isinstance(template, unicode):
template = template.decode('utf-8') template = template.decode('utf-8')
app_id = str(getattr(mdata, 'application_id', '')) app_id = str(getattr(mdata, 'application_id', ''))
# The db id will be in the created filename # The db id will be in the created filename
extra_components = get_components(template, mdata, fname, extra_components = get_components(template, mdata, fname,
length=250-len(app_id)-1) timefmt=opts.send_timefmt, length=250-len(app_id)-1)
if not extra_components: if not extra_components:
extra_components.append(sanitize(self.filename_callback(fname, extra_components.append(sanitize(self.filename_callback(fname,
mdata))) mdata)))

View File

@ -343,8 +343,11 @@ class Metadata(object):
def format_rating(self): def format_rating(self):
return unicode(self.rating) return unicode(self.rating)
def format_field(self, key, ignore_series_index=False, def format_field(self, key):
return_multiples_as_list=False): name, val, ign, ign = self.format_field_extended(key)
return (name, val)
def format_field_extended(self, key):
from calibre.ebooks.metadata import authors_to_string from calibre.ebooks.metadata import authors_to_string
''' '''
returns the tuple (field_name, formatted_value) returns the tuple (field_name, formatted_value)
@ -352,43 +355,41 @@ class Metadata(object):
if key in self.user_metadata_keys: if key in self.user_metadata_keys:
res = self.get(key, None) res = self.get(key, None)
if res is None or res == '': if res is None or res == '':
return (None, None) return (None, None, None, None)
orig_res = res
cmeta = self.get_user_metadata(key, make_copy=False) cmeta = self.get_user_metadata(key, make_copy=False)
name = unicode(cmeta['name']) name = unicode(cmeta['name'])
datatype = cmeta['datatype'] datatype = cmeta['datatype']
if datatype == 'text' and cmeta['is_multiple']: if datatype == 'text' and cmeta['is_multiple']:
if not return_multiples_as_list:
res = u', '.join(res) res = u', '.join(res)
elif datatype == 'series': elif datatype == 'series':
if not ignore_series_index:
res = res + \ res = res + \
' [%s]'%self.format_series_index(val=self.get_extra(key)) ' [%s]'%self.format_series_index(val=self.get_extra(key))
elif datatype == 'datetime': elif datatype == 'datetime':
res = format_date(res, cmeta['display'].get('date_format','dd MMM yyyy')) res = format_date(res, cmeta['display'].get('date_format','dd MMM yyyy'))
elif datatype == 'bool': elif datatype == 'bool':
res = _('Yes') if res else _('No') res = _('Yes') if res else _('No')
return (name, res) return (name, res, orig_res, cmeta)
if key in field_metadata and field_metadata[key]['kind'] == 'field': if key in field_metadata and field_metadata[key]['kind'] == 'field':
res = self.get(key, None) res = self.get(key, None)
if res is None or res == '': if res is None or res == '':
return (None, None) return (None, None, None, None)
orig_res = res
fmeta = field_metadata[key] fmeta = field_metadata[key]
name = unicode(fmeta['name']) name = unicode(fmeta['name'])
datatype = fmeta['datatype'] datatype = fmeta['datatype']
if key == 'authors': if key == 'authors':
res = authors_to_string(res) res = authors_to_string(res)
elif datatype == 'text' and fmeta['is_multiple']: elif datatype == 'text' and fmeta['is_multiple']:
if not return_multiples_as_list:
res = u', '.join(res) res = u', '.join(res)
elif datatype == 'series': elif datatype == 'series':
if not ignore_series_index:
res = res + ' [%s]'%self.format_series_index() res = res + ' [%s]'%self.format_series_index()
elif datatype == 'datetime': elif datatype == 'datetime':
res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy')) res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy'))
return (name, res) return (name, res, orig_res, fmeta)
return (None, None) return (None, None, None, None)
def __unicode__(self): def __unicode__(self):
from calibre.ebooks.metadata import authors_to_string from calibre.ebooks.metadata import authors_to_string

View File

@ -230,7 +230,7 @@ class AddAction(InterfaceAction):
self._files_added(paths, names, infos, on_card=on_card) self._files_added(paths, names, infos, on_card=on_card)
# set the in-library flags, and as a consequence send the library's # set the in-library flags, and as a consequence send the library's
# metadata for this book to the device. This sets the uuid to the # metadata for this book to the device. This sets the uuid to the
# correct value. # correct value. Note that set_books_in_library might sync_booklists
self.gui.set_books_in_library(booklists=[model.db], reset=True) self.gui.set_books_in_library(booklists=[model.db], reset=True)
model.reset() model.reset()

View File

@ -745,6 +745,7 @@ class DeviceMixin(object): # {{{
if job.failed: if job.failed:
self.device_job_exception(job) self.device_job_exception(job)
return return
# set_books_in_library might schedule a sync_booklists job
self.set_books_in_library(job.result, reset=True) self.set_books_in_library(job.result, reset=True)
mainlist, cardalist, cardblist = job.result mainlist, cardalist, cardblist = job.result
self.memory_view.set_database(mainlist) self.memory_view.set_database(mainlist)
@ -789,11 +790,12 @@ class DeviceMixin(object): # {{{
self.device_manager.remove_books_from_metadata(paths, self.device_manager.remove_books_from_metadata(paths,
self.booklists()) self.booklists())
model.paths_deleted(paths) model.paths_deleted(paths)
self.upload_booklists()
# Force recomputation the library's ondevice info. We need to call # Force recomputation the library's ondevice info. We need to call
# set_books_in_library even though books were not added because # set_books_in_library even though books were not added because
# the deleted book might have been an exact match. # the deleted book might have been an exact match. Upload the booklists
self.set_books_in_library(self.booklists(), reset=True) # if set_books_in_library did not.
if not self.set_books_in_library(self.booklists(), reset=True):
self.upload_booklists()
self.book_on_device(None, None, reset=True) self.book_on_device(None, None, reset=True)
# We need to reset the ondevice flags in the library. Use a big hammer, # We need to reset the ondevice flags in the library. Use a big hammer,
# so we don't need to worry about whether some succeeded or not. # so we don't need to worry about whether some succeeded or not.
@ -1280,8 +1282,6 @@ class DeviceMixin(object): # {{{
self.device_manager.add_books_to_metadata(job.result, self.device_manager.add_books_to_metadata(job.result,
metadata, self.booklists()) metadata, self.booklists())
self.upload_booklists()
books_to_be_deleted = [] books_to_be_deleted = []
if memory and memory[1]: if memory and memory[1]:
books_to_be_deleted = memory[1] books_to_be_deleted = memory[1]
@ -1291,12 +1291,15 @@ class DeviceMixin(object): # {{{
# book already there with a different book. This happens frequently in # book already there with a different book. This happens frequently in
# news. When this happens, the book match indication will be wrong # news. When this happens, the book match indication will be wrong
# because the UUID changed. Force both the device and the library view # because the UUID changed. Force both the device and the library view
# to refresh the flags. # to refresh the flags. Set_books_in_library could upload the booklists.
self.set_books_in_library(self.booklists(), reset=True) # If it does not, then do it here.
if not self.set_books_in_library(self.booklists(), reset=True):
self.upload_booklists()
self.book_on_device(None, reset=True) self.book_on_device(None, reset=True)
self.refresh_ondevice_info(device_connected = True) self.refresh_ondevice_info(device_connected = True)
view = self.card_a_view if on_card == 'carda' else self.card_b_view if on_card == 'cardb' else self.memory_view view = self.card_a_view if on_card == 'carda' else \
self.card_b_view if on_card == 'cardb' else self.memory_view
view.model().resort(reset=False) view.model().resort(reset=False)
view.model().research() view.model().research()
for f in files: for f in files:
@ -1371,7 +1374,7 @@ class DeviceMixin(object): # {{{
try: try:
db = self.library_view.model().db db = self.library_view.model().db
except: except:
return return False
# Build a cache (map) of the library, so the search isn't On**2 # Build a cache (map) of the library, so the search isn't On**2
self.db_book_title_cache = {} self.db_book_title_cache = {}
self.db_book_uuid_cache = {} self.db_book_uuid_cache = {}
@ -1466,10 +1469,13 @@ class DeviceMixin(object): # {{{
# Set author_sort if it isn't already # Set author_sort if it isn't already
asort = getattr(book, 'author_sort', None) asort = getattr(book, 'author_sort', None)
if not asort and book.authors: if not asort and book.authors:
book.author_sort = self.library_view.model().db.author_sort_from_authors(book.authors) book.author_sort = self.library_view.model().db.\
author_sort_from_authors(book.authors)
if update_metadata: if update_metadata:
if self.device_manager.is_device_connected: if self.device_manager.is_device_connected:
self.device_manager.sync_booklists(None, booklists) self.device_manager.sync_booklists(
Dispatcher(self.metadata_synced), booklists)
return update_metadata
# }}} # }}}

View File

@ -22,6 +22,9 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r = self.register r = self.register
for x in ('send_timefmt',):
r(x, self.proxy)
choices = [(_('Manual management'), 'manual'), choices = [(_('Manual management'), 'manual'),
(_('Only on send'), 'on_send'), (_('Only on send'), 'on_send'),
(_('Automatic management'), 'on_connect')] (_('Automatic management'), 'on_connect')]

View File

@ -80,7 +80,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="3"> <item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Format &amp;dates as:</string>
</property>
<property name="buddy">
<cstring>opt_send_timefmt</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="opt_send_timefmt"/>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label_43"> <widget class="QLabel" name="label_43">
<property name="text"> <property name="text">
<string>Here you can control how calibre will save your books when you click the Send to Device button. This setting can be overriden for individual devices by customizing the device interface plugins in Preferences-&gt;Advanced-&gt;Plugins</string> <string>Here you can control how calibre will save your books when you click the Send to Device button. This setting can be overriden for individual devices by customizing the device interface plugins in Preferences-&gt;Advanced-&gt;Plugins</string>

View File

@ -84,6 +84,9 @@ def config(defaults=None):
x('timefmt', default='%b, %Y', x('timefmt', default='%b, %Y',
help=_('The format in which to display dates. %d - day, %b - month, ' help=_('The format in which to display dates. %d - day, %b - month, '
'%Y - year. Default is: %b, %Y')) '%Y - year. Default is: %b, %Y'))
x('send_timefmt', default='%b, %Y',
help=_('The format in which to display dates. %d - day, %b - month, '
'%Y - year. Default is: %b, %Y'))
x('to_lowercase', default=False, x('to_lowercase', default=False,
help=_('Convert paths to lowercase.')) help=_('Convert paths to lowercase.'))
x('replace_whitespace', default=False, x('replace_whitespace', default=False,