diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index 20a0d9c608..6d3ecfd1a0 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -4,14 +4,13 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' """ -Provides abstraction for metadata reading.writing from a variety of ebook formats. +Provides abstraction for metadata reading.writing from a variety of ebook formats. """ import os, mimetypes, sys from urllib import unquote, quote from urlparse import urlparse -from calibre.constants import __version__ as VERSION from calibre import relpath from calibre.utils.config import OptionParser @@ -51,17 +50,17 @@ def get_parser(extension): class Resource(object): ''' - Represents a resource (usually a file on the filesystem or a URL pointing + Represents a resource (usually a file on the filesystem or a URL pointing to the web. Such resources are commonly referred to in OPF files. - + They have the interface: - + :member:`path` :member:`mime_type` :method:`href` - + ''' - + def __init__(self, href_or_path, basedir=os.getcwd(), is_path=True): self._href = None self._basedir = basedir @@ -91,13 +90,13 @@ class Resource(object): pc = unquote(pc).decode('utf-8') self.path = os.path.abspath(os.path.join(basedir, pc.replace('/', os.sep))) self.fragment = unquote(url[-1]) - - + + def href(self, basedir=None): ''' Return a URL pointing to this resource. If it is a file on the filesystem the URL is relative to `basedir`. - + `basedir`: If None, the basedir of this resource is used (see :method:`set_basedir`). If this resource has no basedir, then the current working directory is used as the basedir. ''' @@ -119,54 +118,54 @@ class Resource(object): if isinstance(rpath, unicode): rpath = rpath.encode('utf-8') return quote(rpath.replace(os.sep, '/'))+frag - + def set_basedir(self, path): self._basedir = path - + def basedir(self): return self._basedir - + def __repr__(self): return 'Resource(%s, %s)'%(repr(self.path), repr(self.href())) - - + + class ResourceCollection(object): - + def __init__(self): self._resources = [] - + def __iter__(self): for r in self._resources: yield r - + def __len__(self): return len(self._resources) - + def __getitem__(self, index): return self._resources[index] - + def __bool__(self): return len(self._resources) > 0 - + def __str__(self): resources = map(repr, self) return '[%s]'%', '.join(resources) - + def __repr__(self): return str(self) - + def append(self, resource): if not isinstance(resource, Resource): raise ValueError('Can only append objects of type Resource') self._resources.append(resource) - + def remove(self, resource): self._resources.remove(resource) - + def replace(self, start, end, items): 'Same as list[start:end] = items' self._resources[start:end] = items - + @staticmethod def from_directory_contents(top, topdown=True): collection = ResourceCollection() @@ -176,28 +175,28 @@ class ResourceCollection(object): res.set_basedir(top) collection.append(res) return collection - + def set_basedir(self, path): for res in self: res.set_basedir(path) - + class MetaInformation(object): '''Convenient encapsulation of book metadata''' - + @staticmethod def copy(mi): ans = MetaInformation(mi.title, mi.authors) for attr in ('author_sort', 'title_sort', 'comments', 'category', 'publisher', 'series', 'series_index', 'rating', 'isbn', 'tags', 'cover_data', 'application_id', 'guide', - 'manifest', 'spine', 'toc', 'cover', 'language', + 'manifest', 'spine', 'toc', 'cover', 'language', 'book_producer', 'timestamp'): if hasattr(mi, attr): setattr(ans, attr, getattr(mi, attr)) - - def __init__(self, title, authors=[_('Unknown')]): + + def __init__(self, title, authors=(_('Unknown'),)): ''' @param title: title or "Unknown" or a MetaInformation object @param authors: List of strings or [] @@ -208,20 +207,20 @@ class MetaInformation(object): title = mi.title authors = mi.authors self.title = title - self.author = authors # Needed for backward compatibility + self.author = list(authors) # Needed for backward compatibility #: List of strings or [] - self.authors = authors + self.authors = list(authors) self.tags = getattr(mi, 'tags', []) #: mi.cover_data = (ext, data) self.cover_data = getattr(mi, 'cover_data', (None, None)) - + for x in ('author_sort', 'title_sort', 'comments', 'category', 'publisher', 'series', 'series_index', 'rating', 'isbn', 'language', 'application_id', 'manifest', 'toc', 'spine', 'guide', 'cover', 'book_producer', 'timestamp' ): setattr(self, x, getattr(mi, x, None)) - + def smart_update(self, mi): ''' Merge the information in C{mi} into self. In case of conflicts, the information @@ -229,26 +228,26 @@ class MetaInformation(object): ''' if mi.title and mi.title != _('Unknown'): self.title = mi.title - + if mi.authors and mi.authors[0] != _('Unknown'): self.authors = mi.authors - + for attr in ('author_sort', 'title_sort', 'category', 'publisher', 'series', 'series_index', 'rating', - 'isbn', 'application_id', 'manifest', 'spine', 'toc', - 'cover', 'language', 'guide', 'book_producer', + 'isbn', 'application_id', 'manifest', 'spine', 'toc', + 'cover', 'language', 'guide', 'book_producer', 'timestamp'): if hasattr(mi, attr): val = getattr(mi, attr) if val is not None: setattr(self, attr, val) - + self.tags += mi.tags self.tags = list(set(self.tags)) - + if getattr(mi, 'cover_data', None) and mi.cover_data[0] is not None: self.cover_data = mi.cover_data - + my_comments = getattr(self, 'comments', '') other_comments = getattr(mi, 'comments', '') if not my_comments: @@ -257,14 +256,14 @@ class MetaInformation(object): other_comments = '' if len(other_comments.strip()) > len(my_comments.strip()): self.comments = other_comments - + def format_series_index(self): try: x = float(self.series_index) except ValueError: x = 1.0 return '%d'%x if int(x) == x else '%.2f'%x - + def __unicode__(self): ans = u'' ans += u'Title : ' + unicode(self.title) + u'\n' @@ -275,7 +274,7 @@ class MetaInformation(object): ans += u'Publisher: '+ unicode(self.publisher) + u'\n' if getattr(self, 'book_producer', False): ans += u'Producer : '+ unicode(self.book_producer) + u'\n' - if self.category: + if self.category: ans += u'Category : ' + unicode(self.category) + u'\n' if self.comments: ans += u'Comments : ' + unicode(self.comments) + u'\n' @@ -284,13 +283,13 @@ class MetaInformation(object): if self.tags: ans += u'Tags : ' + u', '.join([unicode(t) for t in self.tags]) + '\n' if self.series: - ans += u'Series : '+unicode(self.series) + ' #%s\n'%self.format_series_index() + ans += u'Series : '+unicode(self.series) + ' #%s\n'%self.format_series_index() if self.language: ans += u'Language : ' + unicode(self.language) + u'\n' if self.timestamp is not None: ans += u'Timestamp : ' + self.timestamp.isoformat(' ') return ans.strip() - + def to_html(self): ans = [(_('Title'), unicode(self.title))] ans += [(_('Author(s)'), (authors_to_string(self.authors) if self.authors else _('Unknown')))] @@ -307,9 +306,9 @@ class MetaInformation(object): for i, x in enumerate(ans): ans[i] = u'%s%s'%x return u'%s
'%u'\n'.join(ans) - + def __str__(self): return self.__unicode__().encode('utf-8') - + def __nonzero__(self): return bool(self.title or self.author or self.comments or self.category) diff --git a/src/calibre/gui2/dialogs/config.py b/src/calibre/gui2/dialogs/config.py index 1d1b220f60..831d44251e 100644 --- a/src/calibre/gui2/dialogs/config.py +++ b/src/calibre/gui2/dialogs/config.py @@ -397,6 +397,9 @@ class ConfigDialog(QDialog, Ui_Dialog): self.separate_cover_flow.setChecked(config['separate_cover_flow']) self.setup_email_page() self.category_view.setCurrentIndex(self.category_view.model().index(0)) + self.delete_news.setEnabled(bool(self.sync_news.isChecked())) + self.connect(self.sync_news, SIGNAL('toggled(bool)'), + self.delete_news.setEnabled) def setup_email_page(self): opts = smtp_prefs().parse() diff --git a/src/calibre/gui2/dialogs/config.ui b/src/calibre/gui2/dialogs/config.ui index a75a6f0a8d..9afcac8914 100644 --- a/src/calibre/gui2/dialogs/config.ui +++ b/src/calibre/gui2/dialogs/config.ui @@ -371,7 +371,7 @@ - &Delete news from library when it is sent to reader + &Delete news from library when it is automatically sent to reader