\n
' + match.group(1) + '
'), + (re.compile(u'\n
' + match.group('break') + '
'), # Remove page links (re.compile(r'', re.IGNORECASE), lambda match: ''), diff --git a/src/calibre/ebooks/metadata/book/base.py b/src/calibre/ebooks/metadata/book/base.py index 5f1841d518..3099de12e4 100644 --- a/src/calibre/ebooks/metadata/book/base.py +++ b/src/calibre/ebooks/metadata/book/base.py @@ -120,7 +120,11 @@ class Metadata(object): _('TEMPLATE ERROR'), self).strip() return val - + if field.startswith('#') and field.endswith('_index'): + try: + return self.get_extra(field[:-6]) + except: + pass raise AttributeError( 'Metadata object has no attribute named: '+ repr(field)) @@ -170,11 +174,6 @@ class Metadata(object): try: return self.__getattribute__(field) except AttributeError: - if field.startswith('#') and field.endswith('_index'): - try: - return self.get_extra(field[:-6]) - except: - pass return default def get_extra(self, field, default=None): @@ -631,7 +630,7 @@ class Metadata(object): res = format_date(res, fmeta['display'].get('date_format','dd MMM yyyy')) elif datatype == 'rating': res = res/2.0 - elif key in ('book_size', 'size'): + elif key == 'size': res = human_readable(res) return (name, unicode(res), orig_res, fmeta) diff --git a/src/calibre/ebooks/metadata/mobi.py b/src/calibre/ebooks/metadata/mobi.py index 15fdceff15..74db3b3a58 100644 --- a/src/calibre/ebooks/metadata/mobi.py +++ b/src/calibre/ebooks/metadata/mobi.py @@ -400,7 +400,8 @@ class MetadataUpdater(object): if getattr(self, 'exth', None) is None: raise MobiError('No existing EXTH record. Cannot update metadata.') - self.record0[92:96] = iana2mobi(mi.language) + if not mi.is_null('language'): + self.record0[92:96] = iana2mobi(mi.language) self.create_exth(exth=exth, new_title=mi.title) # Fetch updated timestamp, cover_record, thumbnail_record diff --git a/src/calibre/ebooks/metadata/sources/amazon.py b/src/calibre/ebooks/metadata/sources/amazon.py index 24df68e51d..8483698e28 100644 --- a/src/calibre/ebooks/metadata/sources/amazon.py +++ b/src/calibre/ebooks/metadata/sources/amazon.py @@ -301,7 +301,7 @@ class Amazon(Source): if asin is None: asin = identifiers.get('asin', None) if asin: - return 'http://amzn.com/%s'%asin + return ('amazon', asin, 'http://amzn.com/%s'%asin) # }}} def create_query(self, log, title=None, authors=None, identifiers={}): # {{{ diff --git a/src/calibre/ebooks/metadata/sources/base.py b/src/calibre/ebooks/metadata/sources/base.py index eb0277bd3f..e67b87efbd 100644 --- a/src/calibre/ebooks/metadata/sources/base.py +++ b/src/calibre/ebooks/metadata/sources/base.py @@ -56,7 +56,8 @@ class InternalMetadataCompareKeyGen(object): ''' Generate a sort key for comparison of the relevance of Metadata objects, - given a search query. + given a search query. This is used only to compare results from the same + metadata source, not across different sources. The sort key ensures that an ascending order sort is a sort by order of decreasing relevance. @@ -374,7 +375,11 @@ class Source(Plugin): def get_book_url(self, identifiers): ''' - Return the URL for the book identified by identifiers at this source. + Return a 3-tuple or None. The 3-tuple is of the form: + (identifier_type, identifier_value, URL). + The URL is the URL for the book identified by identifiers at this + source. identifier_type, identifier_value specify the identifier + corresponding to the URL. This URL must be browseable to by a human using a browser. It is meant to provide a clickable link for the user to easily visit the books page at this source. diff --git a/src/calibre/ebooks/metadata/sources/google.py b/src/calibre/ebooks/metadata/sources/google.py index 4133d4d527..b479368bac 100644 --- a/src/calibre/ebooks/metadata/sources/google.py +++ b/src/calibre/ebooks/metadata/sources/google.py @@ -173,7 +173,7 @@ class GoogleBooks(Source): def get_book_url(self, identifiers): # {{{ goog = identifiers.get('google', None) if goog is not None: - return 'http://books.google.com/books?id=%s'%goog + return ('google', goog, 'http://books.google.com/books?id=%s'%goog) # }}} def create_query(self, log, title=None, authors=None, identifiers={}): # {{{ diff --git a/src/calibre/ebooks/metadata/sources/identify.py b/src/calibre/ebooks/metadata/sources/identify.py index 8771274f92..9a9e5aa164 100644 --- a/src/calibre/ebooks/metadata/sources/identify.py +++ b/src/calibre/ebooks/metadata/sources/identify.py @@ -435,18 +435,30 @@ def identify(log, abort, # {{{ # }}} def urls_from_identifiers(identifiers): # {{{ + identifiers = dict([(k.lower(), v) for k, v in identifiers.iteritems()]) ans = [] for plugin in all_metadata_plugins(): try: - url = plugin.get_book_url(identifiers) - if url is not None: - ans.append((plugin.name, url)) + id_type, id_val, url = plugin.get_book_url(identifiers) + ans.append((plugin.name, id_type, id_val, url)) except: pass isbn = identifiers.get('isbn', None) if isbn: - ans.append((isbn, - 'http://www.worldcat.org/search?q=bn%%3A%s&qt=advanced'%isbn)) + ans.append((isbn, 'isbn', isbn, + 'http://www.worldcat.org/isbn/'+isbn)) + doi = identifiers.get('doi', None) + if doi: + ans.append(('DOI', 'doi', doi, + 'http://dx.doi.org/'+doi)) + arxiv = identifiers.get('arxiv', None) + if arxiv: + ans.append(('arXiv', 'arxiv', arxiv, + 'http://arxiv.org/abs/'+arxiv)) + oclc = identifiers.get('oclc', None) + if oclc: + ans.append(('OCLC', 'oclc', oclc, + 'http://www.worldcat.org/oclc/'+oclc)) return ans # }}} diff --git a/src/calibre/ebooks/metadata/sources/overdrive.py b/src/calibre/ebooks/metadata/sources/overdrive.py index 67eac7e337..b2ea36c0ac 100755 --- a/src/calibre/ebooks/metadata/sources/overdrive.py +++ b/src/calibre/ebooks/metadata/sources/overdrive.py @@ -272,7 +272,7 @@ class OverDrive(Source): creators = creators.split(', ') # if an exact match in a preferred format occurs - if ((author and creators[0] == author[0]) or (not author and not creators)) and od_title.lower() == title.lower() and int(formatid) in [1, 50, 410, 900] and thumbimage: + if ((author and creators and creators[0] == author[0]) or (not author and not creators)) and od_title.lower() == title.lower() and int(formatid) in [1, 50, 410, 900] and thumbimage: return self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid) else: @@ -298,7 +298,7 @@ class OverDrive(Source): close_matches.insert(0, self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid)) else: close_matches.append(self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid)) - + elif close_title_match and close_author_match and int(formatid) in [1, 50, 410, 900]: close_matches.append(self.format_results(reserveid, od_title, subtitle, series, publisher, creators, thumbimage, worldcatlink, formatid)) diff --git a/src/calibre/ebooks/metadata/worker.py b/src/calibre/ebooks/metadata/worker.py index d059d7e34c..c335cc4c13 100644 --- a/src/calibre/ebooks/metadata/worker.py +++ b/src/calibre/ebooks/metadata/worker.py @@ -222,7 +222,7 @@ class SaveWorker(Thread): if isbytestring(fpath): fpath = fpath.decode(filesystem_encoding) formats[fmt.lower()] = fpath - data[i] = [opf, cpath, formats] + data[i] = [opf, cpath, formats, mi.last_modified.isoformat()] return data def run(self): diff --git a/src/calibre/ebooks/pdb/plucker/reader.py b/src/calibre/ebooks/pdb/plucker/reader.py index 39ceb33b13..d782e4e97c 100644 --- a/src/calibre/ebooks/pdb/plucker/reader.py +++ b/src/calibre/ebooks/pdb/plucker/reader.py @@ -16,6 +16,7 @@ from calibre import CurrentDir from calibre.ebooks.pdb.formatreader import FormatReader from calibre.ptempfile import TemporaryFile from calibre.utils.magick import Image, create_canvas +from calibre.ebooks.compression.palmdoc import decompress_doc DATATYPE_PHTML = 0 DATATYPE_PHTML_COMPRESSED = 1 diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index f1357728ec..60d2a0a7dd 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -739,12 +739,6 @@ def build_forms(srcdir, info=None): dat = dat.replace('from QtWebKit.QWebView import QWebView', 'from PyQt4 import QtWebKit\nfrom PyQt4.QtWebKit import QWebView') - if form.endswith('viewer%smain.ui'%os.sep): - info('\t\tPromoting WebView') - dat = dat.replace('self.view = QtWebKit.QWebView(', 'self.view = DocumentView(') - dat = dat.replace('self.view = QWebView(', 'self.view = DocumentView(') - dat += '\n\nfrom calibre.gui2.viewer.documentview import DocumentView' - open(compiled_form, 'wb').write(dat) _df = os.environ.get('CALIBRE_DEVELOP_FROM', None) diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index a2ee6d343b..f94e179166 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -17,13 +17,13 @@ from calibre.gui2.dnd import (dnd_has_image, dnd_get_image, dnd_get_files, from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks.metadata.book.base import (field_metadata, Metadata) from calibre.ebooks.metadata import fmt_sidx +from calibre.ebooks.metadata.sources.identify import urls_from_identifiers from calibre.constants import filesystem_encoding from calibre.library.comments import comments_to_html from calibre.gui2 import (config, open_local_file, open_url, pixmap_to_data, gprefs) from calibre.utils.icu import sort_key - def render_html(mi, css, vertical, widget, all_fields=False): # {{{ table = render_data(mi, all_fields=all_fields, use_roman_numbers=config['use_roman_numerals_for_series_number']) @@ -114,17 +114,20 @@ def render_data(mi, use_roman_numbers=True, all_fields=False): ans.append((field, u''+_('Quick create:')
for col, name in [('isbn', _('ISBN')), ('formats', _('Formats')),
- ('last_modified', _('Modified Date')), ('yesno', _('Yes/No')),
+ ('yesno', _('Yes/No')),
('tags', _('Tags')), ('series', _('Series')), ('rating',
_('Rating')), ('people', _("People's names"))]:
text += ' %s,'%(col, name)
@@ -150,7 +150,6 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
'tags': _('My Tags'),
'series': _('My Series'),
'rating': _('My Rating'),
- 'last_modified':_('Modified Date'),
'people': _('People')}[which])
self.is_names.setChecked(which == 'people')
if self.composite_box.isVisible():
@@ -158,9 +157,8 @@ class CreateCustomColumn(QDialog, Ui_QCreateCustomColumn):
{
'isbn': '{identifiers:select(isbn)}',
'formats': '{formats}',
- 'last_modified':'''{last_modified:'format_date($, "dd MMM yyyy")'}'''
}[which])
- self.composite_sort_by.setCurrentIndex(2 if which == 'last_modified' else 0)
+ self.composite_sort_by.setCurrentIndex(0)
def datatype_changed(self, *args):
try:
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index bae08f5455..620113cc3f 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -235,6 +235,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
gui.library_view.refresh_book_details()
if __name__ == '__main__':
- app = QApplication([])
+ from calibre.gui2 import Application
+ app = Application([])
test_widget('Interface', 'Look & Feel')
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index 3d8a818e1e..244b811cbd 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -7,28 +7,27 @@
'+_('The selected search will be ' + 'permanently deleted. Are you sure?') + +'
', 'saved_search_delete', self): + return + ss = saved_searches().lookup(unicode(self.currentText())) + if ss is None: + return + saved_searches().delete(unicode(self.currentText())) + self.clear() + self.search_box.clear() + self.changed.emit() + # SIGNALed from the main UI def copy_search_button_clicked (self): idx = self.currentIndex(); @@ -428,6 +449,22 @@ class SavedSearchBoxMixin(object): # {{{ for x in ('copy', 'save'): b = getattr(self, x+'_search_button') b.setStatusTip(b.toolTip()) + self.save_search_button.setToolTip('' + + _("Save current search under the name shown in the box. " + "Press and hold for a pop-up options menu.") + '
') + self.save_search_button.setMenu(QMenu()) + self.save_search_button.menu().addAction( + QIcon(I('plus.png')), + _('Create saved search'), + self.saved_search.save_search_button_clicked) + self.save_search_button.menu().addAction( + QIcon(I('trash.png')), + _('Delete saved search'), + self.saved_search.delete_current_search) + self.save_search_button.menu().addAction( + QIcon(I('search.png')), + _('Manage saved searches'), + partial(self.do_saved_search_edit, None)) def saved_searches_changed(self, set_restriction=None, recount=True): p = sorted(saved_searches().names(), key=sort_key) diff --git a/src/calibre/gui2/viewer/main.ui b/src/calibre/gui2/viewer/main.ui index 04166fe2cf..3137ad2e07 100644 --- a/src/calibre/gui2/viewer/main.ui +++ b/src/calibre/gui2/viewer/main.ui @@ -33,24 +33,21 @@