From 99ad2c86b5cd71541b2f9370700ee14ec908c7f3 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Tue, 24 May 2011 08:23:50 +0100
Subject: [PATCH 1/6] Small change to help text. Add tooltip to wizard button.
Have tag column expand in tag wizard when resizing dialog.
---
src/calibre/gui2/dialogs/template_line_editor.py | 1 +
src/calibre/gui2/preferences/look_feel.py | 4 ++--
src/calibre/gui2/preferences/look_feel.ui | 15 +++++++++++++++
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/calibre/gui2/dialogs/template_line_editor.py b/src/calibre/gui2/dialogs/template_line_editor.py
index 95727e442b..26f4dd0753 100644
--- a/src/calibre/gui2/dialogs/template_line_editor.py
+++ b/src/calibre/gui2/dialogs/template_line_editor.py
@@ -63,6 +63,7 @@ class TagWizard(QDialog):
self.tags = tags
l = QGridLayout()
self.setLayout(l)
+ l.setColumnStretch(0, 1)
l.addWidget(QLabel(_('Tag Value')), 0, 0, 1, 1)
l.addWidget(QLabel(_('Color')), 0, 1, 1, 1)
self.tagboxes = []
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index 483934825d..49bfb1df1a 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -167,8 +167,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
''
'tutorial on using templates.') +
'
' +
- _('If you want to color a field based on tags, then right-click '
- 'in an empty template line and choose tags wizard. '
+ _('If you want to color a field based on tags, then click the '
+ 'button next to an empty line to open the tags wizard. '
'It will build a template for you. You can later edit that '
'template with the same wizard. If you edit it by hand, the '
'wizard might not work or might restore old values.') +
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index a67a3585cb..fe6134f235 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -442,6 +442,9 @@ then the tags will be displayed each on their own line.
:/images/wizard.png:/images/wizard.png
+
+ Open the tags wizard.
+
-
@@ -456,6 +459,9 @@ then the tags will be displayed each on their own line.
:/images/wizard.png:/images/wizard.png
+
+ Open the tags wizard.
+
-
@@ -470,6 +476,9 @@ then the tags will be displayed each on their own line.
:/images/wizard.png:/images/wizard.png
+
+ Open the tags wizard.
+
-
@@ -484,6 +493,9 @@ then the tags will be displayed each on their own line.
:/images/wizard.png:/images/wizard.png
+
+ Open the tags wizard.
+
-
@@ -498,6 +510,9 @@ then the tags will be displayed each on their own line.
:/images/wizard.png:/images/wizard.png
+
+ Open the tags wizard.
+
-
From 1bb4911ece2374f3fc2fce0e57383fc11f847e8c Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 24 May 2011 10:54:06 -0600
Subject: [PATCH 2/6] ...
---
src/calibre/linux.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/calibre/linux.py b/src/calibre/linux.py
index 1e7a62b869..9e58d4f638 100644
--- a/src/calibre/linux.py
+++ b/src/calibre/linux.py
@@ -356,7 +356,7 @@ class PostInstall:
mimetypes = set([])
for x in all_input_formats():
mt = guess_type('dummy.'+x)[0]
- if mt and 'chemical' not in mt:
+ if mt and 'chemical' not in mt and 'ctc-posml' not in mt:
mimetypes.add(mt)
def write_mimetypes(f):
@@ -376,11 +376,10 @@ class PostInstall:
des = ('calibre-gui.desktop', 'calibre-lrfviewer.desktop',
'calibre-ebook-viewer.desktop')
for x in des:
- cmd = ['xdg-desktop-menu', 'install', './'+x]
- if x != des[-1]:
- cmd.insert(2, '--noupdate')
+ cmd = ['xdg-desktop-menu', 'install', '--noupdate', './'+x]
check_call(' '.join(cmd), shell=True)
self.menu_resources.append(x)
+ check_call(['xdg-desktop-menu', 'forceupdate'])
f = open('calibre-mimetypes', 'wb')
f.write(MIME)
f.close()
From 268a81499cde8ae38063679343306113148b158a Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Tue, 24 May 2011 18:26:04 +0100
Subject: [PATCH 3/6] Change control to a line edit. Improve generated template
code.
---
.../gui2/dialogs/template_line_editor.py | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/calibre/gui2/dialogs/template_line_editor.py b/src/calibre/gui2/dialogs/template_line_editor.py
index 26f4dd0753..98b74b391d 100644
--- a/src/calibre/gui2/dialogs/template_line_editor.py
+++ b/src/calibre/gui2/dialogs/template_line_editor.py
@@ -9,7 +9,7 @@ from PyQt4.Qt import (QLineEdit, QDialog, QGridLayout, QLabel,
QDialogButtonBox, QColor, QComboBox, QIcon)
from calibre.gui2.dialogs.template_dialog import TemplateDialog
-from calibre.gui2.complete import MultiCompleteComboBox
+from calibre.gui2.complete import MultiCompleteLineEdit
from calibre.gui2 import error_dialog
class TemplateLineEditor(QLineEdit):
@@ -64,14 +64,15 @@ class TagWizard(QDialog):
l = QGridLayout()
self.setLayout(l)
l.setColumnStretch(0, 1)
- l.addWidget(QLabel(_('Tag Value')), 0, 0, 1, 1)
+ l.setColumnMinimumWidth(0, 300)
+ l.addWidget(QLabel(_('Tags (more than one per box permitted)')), 0, 0, 1, 1)
l.addWidget(QLabel(_('Color')), 0, 1, 1, 1)
self.tagboxes = []
self.colorboxes = []
self.colors = [unicode(s) for s in list(QColor.colorNames())]
self.colors.insert(0, '')
for i in range(0, 10):
- tb = MultiCompleteComboBox(self)
+ tb = MultiCompleteLineEdit(self)
tb.set_separator(', ')
tb.update_items_cache(self.tags)
self.tagboxes.append(tb)
@@ -102,10 +103,11 @@ class TagWizard(QDialog):
def accepted(self):
res = ("program:\n#tag wizard -- do not directly edit\n"
- " t = field('tags');\n first_non_empty(\n")
+ " t = field('tags');\n first_non_empty(\n")
lines = []
for tb, cb in zip(self.tagboxes, self.colorboxes):
- tags = [t.strip() for t in unicode(tb.currentText()).split(',') if t.strip()]
+ tags = [t.strip() for t in unicode(tb.text()).split(',') if t.strip()]
+ tags = '$|^'.join(tags)
c = unicode(cb.currentText()).strip()
if not tags or not c:
continue
@@ -114,14 +116,13 @@ class TagWizard(QDialog):
_('The color {0} is not valid').format(c),
show=True, show_copy_button=False)
return False
- for t in tags:
- lines.append(" in_list(t, ',', '^{0}$', '{1}', '')".format(t, c))
+ lines.append(" in_list(t, ',', '^{0}$', '{1}', '')".format(tags, c))
res += ',\n'.join(lines)
res += ')\n'
self.template = res
res = ''
for tb, cb in zip(self.tagboxes, self.colorboxes):
- t = unicode(tb.currentText()).strip()
+ t = unicode(tb.text()).strip()
if t.endswith(','):
t = t[:-1]
c = unicode(cb.currentText()).strip()
From 2fec4aa6c3719767d52c8e4558697dbc4f088ebb Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 24 May 2011 13:33:52 -0600
Subject: [PATCH 4/6] ...
---
src/calibre/library/server/base.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/calibre/library/server/base.py b/src/calibre/library/server/base.py
index 862e724809..319feefa44 100644
--- a/src/calibre/library/server/base.py
+++ b/src/calibre/library/server/base.py
@@ -221,7 +221,12 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
if not ip or ip.startswith('127.'):
raise
cherrypy.log('Trying to bind to single interface: '+ip)
+ # Change the host we listen on
cherrypy.config.update({'server.socket_host' : ip})
+ # This ensures that the change is actually applied
+ cherrypy.server.socket_host = ip
+ cherrypy.server.httpserver = cherrypy.server.instance = None
+
cherrypy.engine.start()
self.is_running = True
@@ -231,6 +236,8 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
cherrypy.engine.block()
except Exception as e:
self.exception = e
+ import traceback
+ traceback.print_exc()
finally:
self.is_running = False
try:
From 3a78a875afe7c980aae8497d89e1a1d784335c2f Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 24 May 2011 15:18:47 -0600
Subject: [PATCH 5/6] Amazon metadata download: Use separate identifiers for
country specific downloads so that the links to Amazon in the Book details
panel work when downloading metadata from country specific amazon websites.
Fixes #786146 (German Amazon Metadata)
---
src/calibre/ebooks/metadata/sources/amazon.py | 63 +++++++++++++------
1 file changed, 43 insertions(+), 20 deletions(-)
diff --git a/src/calibre/ebooks/metadata/sources/amazon.py b/src/calibre/ebooks/metadata/sources/amazon.py
index f291959475..7da37ce5af 100644
--- a/src/calibre/ebooks/metadata/sources/amazon.py
+++ b/src/calibre/ebooks/metadata/sources/amazon.py
@@ -29,7 +29,7 @@ class Worker(Thread): # Get details {{{
Get book details from amazons book page in a separate thread
'''
- def __init__(self, url, result_queue, browser, log, relevance, plugin, timeout=20):
+ def __init__(self, url, result_queue, browser, log, relevance, domain, plugin, timeout=20):
Thread.__init__(self)
self.daemon = True
self.url, self.result_queue = url, result_queue
@@ -37,7 +37,7 @@ class Worker(Thread): # Get details {{{
self.relevance, self.plugin = relevance, plugin
self.browser = browser.clone_browser()
self.cover_url = self.amazon_id = self.isbn = None
- self.domain = self.plugin.domain
+ self.domain = domain
months = {
'de': {
@@ -199,7 +199,8 @@ class Worker(Thread): # Get details {{{
return
mi = Metadata(title, authors)
- mi.set_identifier('amazon', asin)
+ idtype = 'amazon' if self.domain == 'com' else 'amazon_'+self.domain
+ mi.set_identifier(idtype, asin)
self.amazon_id = asin
try:
@@ -404,12 +405,30 @@ class Amazon(Source):
'country\'s Amazon website.'), choices=AMAZON_DOMAINS),
)
+ def get_domain_and_asin(self, identifiers):
+ for key, val in identifiers.iteritems():
+ key = key.lower()
+ if key in ('amazon', 'asin'):
+ return 'com', val
+ if key.startswith('amazon_'):
+ domain = key.split('_')[-1]
+ if domain and domain in self.AMAZON_DOMAINS:
+ return domain, val
+ return None, None
+
def get_book_url(self, identifiers): # {{{
- asin = identifiers.get('amazon', None)
- if asin is None:
- asin = identifiers.get('asin', None)
- if asin:
- return ('amazon', asin, 'http://amzn.com/%s'%asin)
+ domain, asin = self.get_domain_and_asin(identifiers)
+ if domain and asin:
+ url = None
+ if domain == 'com':
+ url = 'http://amzn.com/'+asin
+ elif domain == 'uk':
+ url = 'http://www.amazon.co.uk/dp/'+asin
+ else:
+ url = 'http://www.amazon.%s/dp/%s'%(domain, asin)
+ if url:
+ idtype = 'amazon' if self.domain == 'com' else 'amazon_'+self.domain
+ return (idtype, asin, url)
# }}}
@property
@@ -420,8 +439,14 @@ class Amazon(Source):
return domain
- def create_query(self, log, title=None, authors=None, identifiers={}): # {{{
- domain = self.domain
+ def create_query(self, log, title=None, authors=None, identifiers={}, # {{{
+ domain=None):
+ if domain is None:
+ domain = self.domain
+
+ idomain, asin = self.get_domain_and_asin(identifiers)
+ if idomain is not None:
+ domain = idomain
# See the amazon detailed search page to get all options
q = { 'search-alias' : 'aps',
@@ -433,7 +458,6 @@ class Amazon(Source):
else:
q['sort'] = 'relevancerank'
- asin = identifiers.get('amazon', None)
isbn = check_isbn(identifiers.get('isbn', None))
if asin is not None:
@@ -456,23 +480,22 @@ class Amazon(Source):
if not ('field-keywords' in q or 'field-isbn' in q or
('field-title' in q)):
# Insufficient metadata to make an identify query
- return None
+ return None, None
latin1q = dict([(x.encode('latin1', 'ignore'), y.encode('latin1',
'ignore')) for x, y in
q.iteritems()])
+ udomain = domain
if domain == 'uk':
- domain = 'co.uk'
- url = 'http://www.amazon.%s/s/?'%domain + urlencode(latin1q)
- return url
+ udomain = 'co.uk'
+ url = 'http://www.amazon.%s/s/?'%udomain + urlencode(latin1q)
+ return url, domain
# }}}
def get_cached_cover_url(self, identifiers): # {{{
url = None
- asin = identifiers.get('amazon', None)
- if asin is None:
- asin = identifiers.get('asin', None)
+ domain, asin = self.get_domain_and_asin(identifiers)
if asin is None:
isbn = identifiers.get('isbn', None)
if isbn is not None:
@@ -489,7 +512,7 @@ class Amazon(Source):
Note this method will retry without identifiers automatically if no
match is found with identifiers.
'''
- query = self.create_query(log, title=title, authors=authors,
+ query, domain = self.create_query(log, title=title, authors=authors,
identifiers=identifiers)
if query is None:
log.error('Insufficient metadata to construct query')
@@ -571,7 +594,7 @@ class Amazon(Source):
log.error('No matches found with query: %r'%query)
return
- workers = [Worker(url, result_queue, br, log, i, self) for i, url in
+ workers = [Worker(url, result_queue, br, log, i, domain, self) for i, url in
enumerate(matches)]
for w in workers:
From 1395c6d5d814349102d23d9cdfb26af8689b4bb0 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 24 May 2011 15:48:27 -0600
Subject: [PATCH 6/6] EPUB Output: Change any white-space:pre declarations in
the CSS to pre-wrap to accomodate readers that cannot scroll horizontally.
Fixes #786722 (chm to epub conversion fails to reflow text in
tag)
---
src/calibre/ebooks/epub/output.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/calibre/ebooks/epub/output.py b/src/calibre/ebooks/epub/output.py
index 0ed6d7e222..bea90eeba8 100644
--- a/src/calibre/ebooks/epub/output.py
+++ b/src/calibre/ebooks/epub/output.py
@@ -413,6 +413,13 @@ class EPUBOutput(OutputFormatPlugin):
rule.style.removeProperty('margin-left')
# padding-left breaks rendering in webkit and gecko
rule.style.removeProperty('padding-left')
+ # Change whitespace:pre to pre-line to accommodate readers that
+ # cannot scroll horizontally
+ for rule in stylesheet.data.cssRules.rulesOfType(CSSRule.STYLE_RULE):
+ style = rule.style
+ ws = style.getPropertyValue('white-space')
+ if ws == 'pre':
+ style.setProperty('white-space', 'pre-wrap')
# }}}