-
- btc = 1
- headline.extract()
- body.insert(1, headline)
- btc += 1
- if img:
- img.extract()
- body.insert(btc, img)
- btc += 1
- if caption:
- caption.extract()
- body.insert(btc, caption)
- btc += 1
-
- if len(imgs) > 1:
- if True:
- [img.extract() for img in imgs[1:]]
- else:
- # Format the remaining images
- # This doesn't work yet
- for img in imgs[1:]:
- print "img:\n%s\n" % img.prettify()
- divTag = Tag(soup, 'div')
- divTag['class'] = 'image'
-
- # Table for photo and credit
- tableTag = Tag(soup,'table')
-
- # Photo
- trimgTag = Tag(soup, 'tr')
- tdimgTag = Tag(soup, 'td')
- tdimgTag.insert(0,img)
- trimgTag.insert(0,tdimgTag)
- tableTag.insert(0,trimgTag)
-
- # Credit
- trcreditTag = Tag(soup, 'tr')
-
- tdcreditTag = Tag(soup, 'td')
- tdcreditTag['class'] = 'credit'
- try:
- tdcreditTag.insert(0,NavigableString(img['credit']))
- except:
- tdcreditTag.insert(0,NavigableString(''))
- trcreditTag.insert(0,tdcreditTag)
- tableTag.insert(1,trcreditTag)
- divTag.insert(0,tableTag)
- soup.img.replaceWith(divTag)
-
- return soup
-
- def postprocess_book(self, oeb, opts, log) :
-
- def extract_byline(href) :
- #
'' :
- return self.massageNCXText(self.tag_to_string(p,use_alt=False))
- else:
- print "Didn't find
in this soup:\n%s" % soup.prettify()
- return None
-
- # Method entry point here
- # Single section toc looks different than multi-section tocs
- if oeb.toc.depth() == 2 :
- for article in oeb.toc :
- if article.author is None :
- article.author = extract_byline(article.href)
- if article.description is None :
- article.description = extract_description(article.href)
- elif oeb.toc.depth() == 3 :
- for section in oeb.toc :
- for article in section :
- article.author = extract_byline(article.href)
- '''
- if article.author is None :
- article.author = self.massageNCXText(extract_byline(article.href))
- else:
- article.author = self.massageNCXText(article.author)
- '''
- if article.description is None :
- article.description = extract_description(article.href)
-
- def strip_anchors(self,soup):
- paras = soup.findAll(True)
- for para in paras:
- aTags = para.findAll('a')
- for a in aTags:
- if a.img is None:
- a.replaceWith(a.renderContents().decode('cp1252','replace'))
- return soup
diff --git a/src/calibre/devices/kindle/apnx.py b/src/calibre/devices/kindle/apnx.py
index ee519750e0..178c1091f3 100644
--- a/src/calibre/devices/kindle/apnx.py
+++ b/src/calibre/devices/kindle/apnx.py
@@ -164,7 +164,7 @@ def get_pages_accurate(self, mobi_file_path):
if c == '/':
closing = True
continue
- elif c in ('d', 'p'):
+ elif c == 'p':
if closing:
in_p = False
else:
diff --git a/src/calibre/ebooks/htmlz/input.py b/src/calibre/ebooks/htmlz/input.py
index dcf2ed0ed3..d083fcc4ab 100644
--- a/src/calibre/ebooks/htmlz/input.py
+++ b/src/calibre/ebooks/htmlz/input.py
@@ -7,10 +7,12 @@
__docformat__ = 'restructuredtext en'
import os
+import posixpath
-from calibre import walk
+from calibre import guess_type, walk
from calibre.customize.conversion import InputFormatPlugin
from calibre.ebooks.chardet import xml_to_unicode
+from calibre.ebooks.metadata.opf2 import OPF
from calibre.utils.zipfile import ZipFile
class HTMLZInput(InputFormatPlugin):
@@ -27,7 +29,7 @@ def convert(self, stream, options, file_ext, log,
# Extract content from zip archive.
zf = ZipFile(stream)
- zf.extractall('.')
+ zf.extractall()
for x in walk('.'):
if os.path.splitext(x)[1].lower() in ('.html', '.xhtml', '.htm'):
@@ -70,5 +72,24 @@ def convert(self, stream, options, file_ext, log,
from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata
mi = get_file_type_metadata(stream, file_ext)
meta_info_to_oeb_metadata(mi, oeb.metadata, log)
+
+ # Get the cover path from the OPF.
+ cover_href = None
+ opf = None
+ for x in walk('.'):
+ if os.path.splitext(x)[1].lower() in ('.opf'):
+ opf = x
+ break
+ if opf:
+ opf = OPF(opf)
+ cover_href = posixpath.relpath(opf.cover, os.path.dirname(stream.name))
+ # Set the cover.
+ if cover_href:
+ cdata = None
+ with open(cover_href, 'rb') as cf:
+ cdata = cf.read()
+ id, href = oeb.manifest.generate('cover', cover_href)
+ oeb.manifest.add(id, href, guess_type(cover_href)[0], data=cdata)
+ oeb.guide.add('cover', 'Cover', href)
return oeb
diff --git a/src/calibre/ebooks/htmlz/output.py b/src/calibre/ebooks/htmlz/output.py
index 6d2ad54a12..a1ef57af2c 100644
--- a/src/calibre/ebooks/htmlz/output.py
+++ b/src/calibre/ebooks/htmlz/output.py
@@ -7,11 +7,13 @@
__docformat__ = 'restructuredtext en'
import os
+from cStringIO import StringIO
from lxml import etree
from calibre.customize.conversion import OutputFormatPlugin, \
OptionRecommendation
+from calibre.ebooks.metadata.opf2 import OPF, metadata_to_opf
from calibre.ptempfile import TemporaryDirectory
from calibre.utils.zipfile import ZipFile
@@ -79,10 +81,31 @@ def convert(self, oeb_book, output_path, input_plugin, opts, log):
fname = os.path.join(tdir, 'images', images[item.href])
with open(fname, 'wb') as img:
img.write(data)
+
+ # Cover
+ cover_path = None
+ try:
+ cover_data = None
+ if oeb_book.metadata.cover:
+ term = oeb_book.metadata.cover[0].term
+ cover_data = oeb_book.guide[term].item.data
+ if cover_data:
+ from calibre.utils.magick.draw import save_cover_data_to
+ cover_path = os.path.join(tdir, 'cover.jpg')
+ with open(cover_path, 'w') as cf:
+ cf.write('')
+ save_cover_data_to(cover_data, cover_path)
+ except:
+ import traceback
+ traceback.print_exc()
# Metadata
with open(os.path.join(tdir, 'metadata.opf'), 'wb') as mdataf:
- mdataf.write(etree.tostring(oeb_book.metadata.to_opf1()))
+ opf = OPF(StringIO(etree.tostring(oeb_book.metadata.to_opf1())))
+ mi = opf.to_book_metadata()
+ if cover_path:
+ mi.cover = 'cover.jpg'
+ mdataf.write(metadata_to_opf(mi))
htmlz = ZipFile(output_path, 'w')
htmlz.add_dir(tdir)
diff --git a/src/calibre/ebooks/metadata/extz.py b/src/calibre/ebooks/metadata/extz.py
index 18069b2a6a..021450fca5 100644
--- a/src/calibre/ebooks/metadata/extz.py
+++ b/src/calibre/ebooks/metadata/extz.py
@@ -13,7 +13,7 @@
from cStringIO import StringIO
from calibre.ebooks.metadata import MetaInformation
-from calibre.ebooks.metadata.opf2 import OPF
+from calibre.ebooks.metadata.opf2 import OPF, metadata_to_opf
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.zipfile import ZipFile, safe_replace
@@ -31,9 +31,9 @@ def get_metadata(stream, extract_cover=True):
opf = OPF(opf_stream)
mi = opf.to_book_metadata()
if extract_cover:
- cover_name = opf.raster_cover
- if cover_name:
- mi.cover_data = ('jpg', zf.read(cover_name))
+ cover_href = posixpath.relpath(opf.cover, os.path.dirname(stream.name))
+ if cover_href:
+ mi.cover_data = ('jpg', zf.read(cover_href))
except:
return mi
return mi
@@ -59,17 +59,20 @@ def set_metadata(stream, mi):
except:
pass
if new_cdata:
- raster_cover = opf.raster_cover
- if not raster_cover:
- raster_cover = 'cover.jpg'
- cpath = posixpath.join(posixpath.dirname(opf_path), raster_cover)
+ cover = opf.cover
+ if not cover:
+ cover = 'cover.jpg'
+ cpath = posixpath.join(posixpath.dirname(opf_path), cover)
new_cover = _write_new_cover(new_cdata, cpath)
replacements[cpath] = open(new_cover.name, 'rb')
+ mi.cover = cover
# Update the metadata.
- opf.smart_update(mi, replace_metadata=True)
+ old_mi = opf.to_book_metadata()
+ old_mi.smart_update(mi)
+ opf.smart_update(metadata_to_opf(old_mi), replace_metadata=True)
newopf = StringIO(opf.render())
- safe_replace(stream, opf_path, newopf, extra_replacements=replacements)
+ safe_replace(stream, opf_path, newopf, extra_replacements=replacements, add_missing=True)
# Cleanup temporary files.
try:
diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py
index 58c887bfdb..1d91236757 100644
--- a/src/calibre/ebooks/metadata/opf2.py
+++ b/src/calibre/ebooks/metadata/opf2.py
@@ -966,7 +966,9 @@ def raster_cover(self):
cover_id = covers[0].get('content')
for item in self.itermanifest():
if item.get('id', None) == cover_id:
- return item.get('href', None)
+ mt = item.get('media-type', '')
+ if 'xml' not in mt:
+ return item.get('href', None)
@dynamic_property
def cover(self):
diff --git a/src/calibre/ebooks/metadata/sources/identify.py b/src/calibre/ebooks/metadata/sources/identify.py
index 3d4807ac02..1bd071d6f9 100644
--- a/src/calibre/ebooks/metadata/sources/identify.py
+++ b/src/calibre/ebooks/metadata/sources/identify.py
@@ -13,6 +13,7 @@
from threading import Thread
from io import BytesIO
from operator import attrgetter
+from urlparse import urlparse
from calibre.customize.ui import metadata_plugins, all_metadata_plugins
from calibre.ebooks.metadata.sources.base import create_log, msprefs
@@ -458,6 +459,14 @@ def urls_from_identifiers(identifiers): # {{{
if oclc:
ans.append(('OCLC', 'oclc', oclc,
'http://www.worldcat.org/oclc/'+oclc))
+ url = identifiers.get('uri', None)
+ if url is None:
+ url = identifiers.get('url', None)
+ if url and url.startswith('http'):
+ url = url[:8].replace('|', ':') + url[8:].replace('|', ',')
+ parts = urlparse(url)
+ name = parts.netloc
+ ans.append((name, 'url', url, url))
return ans
# }}}
diff --git a/src/calibre/ebooks/odt/input.py b/src/calibre/ebooks/odt/input.py
index 1184148e80..e724acb981 100644
--- a/src/calibre/ebooks/odt/input.py
+++ b/src/calibre/ebooks/odt/input.py
@@ -7,6 +7,8 @@
Convert an ODT file into a Open Ebook
'''
import os
+
+from lxml import etree
from odf.odf2xhtml import ODF2XHTML
from calibre import CurrentDir, walk
@@ -23,7 +25,51 @@ def extract_pictures(self, zf):
with open(name, 'wb') as f:
f.write(data)
- def __call__(self, stream, odir):
+ def filter_css(self, html, log):
+ root = etree.fromstring(html)
+ style = root.xpath('//*[local-name() = "style" and @type="text/css"]')
+ if style:
+ style = style[0]
+ css = style.text
+ if css:
+ style.text, sel_map = self.do_filter_css(css)
+ for x in root.xpath('//*[@class]'):
+ extra = []
+ orig = x.get('class')
+ for cls in orig.split():
+ extra.extend(sel_map.get(cls, []))
+ if extra:
+ x.set('class', orig + ' ' + ' '.join(extra))
+ html = etree.tostring(root, encoding='utf-8',
+ xml_declaration=True)
+ return html
+
+ def do_filter_css(self, css):
+ from cssutils import parseString
+ from cssutils.css import CSSRule
+ sheet = parseString(css)
+ rules = list(sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE))
+ sel_map = {}
+ count = 0
+ for r in rules:
+ # Check if we have only class selectors for this rule
+ nc = [x for x in r.selectorList if not
+ x.selectorText.startswith('.')]
+ if len(r.selectorList) > 1 and not nc:
+ # Replace all the class selectors with a single class selector
+ # This will be added to the class attribute of all elements
+ # that have one of these selectors.
+ replace_name = 'c_odt%d'%count
+ count += 1
+ for sel in r.selectorList:
+ s = sel.selectorText[1:]
+ if s not in sel_map:
+ sel_map[s] = []
+ sel_map[s].append(replace_name)
+ r.selectorText = '.'+replace_name
+ return sheet.cssText, sel_map
+
+ def __call__(self, stream, odir, log):
from calibre.utils.zipfile import ZipFile
from calibre.ebooks.metadata.meta import get_metadata
from calibre.ebooks.metadata.opf2 import OPFCreator
@@ -32,13 +78,17 @@ def __call__(self, stream, odir):
if not os.path.exists(odir):
os.makedirs(odir)
with CurrentDir(odir):
- print 'Extracting ODT file...'
+ log('Extracting ODT file...')
html = self.odf2xhtml(stream)
# A blanket img specification like this causes problems
- # with EPUB output as the contaiing element often has
+ # with EPUB output as the containing element often has
# an absolute height and width set that is larger than
# the available screen real estate
html = html.replace('img { width: 100%; height: 100%; }', '')
+ try:
+ html = self.filter_css(html, log)
+ except:
+ log.exception('Failed to filter CSS, conversion may be slow')
with open('index.xhtml', 'wb') as f:
f.write(html.encode('utf-8'))
zf = ZipFile(stream, 'r')
@@ -67,7 +117,7 @@ class ODTInput(InputFormatPlugin):
def convert(self, stream, options, file_ext, log,
accelerators):
- return Extract()(stream, '.')
+ return Extract()(stream, '.', log)
def postprocess_book(self, oeb, opts, log):
# Fix
constructs as the asinine epubchecker complains
diff --git a/src/calibre/ebooks/oeb/transforms/metadata.py b/src/calibre/ebooks/oeb/transforms/metadata.py
index 19c209b74d..f719ee3eb5 100644
--- a/src/calibre/ebooks/oeb/transforms/metadata.py
+++ b/src/calibre/ebooks/oeb/transforms/metadata.py
@@ -36,7 +36,7 @@ def meta_info_to_oeb_metadata(mi, m, log, override_input_metadata=False):
m.clear('description')
m.add('description', mi.comments)
elif override_input_metadata:
- m.clear('description')
+ m.clear('description')
if not mi.is_null('publisher'):
m.clear('publisher')
m.add('publisher', mi.publisher)
diff --git a/src/calibre/ebooks/rtf/rtfml.py b/src/calibre/ebooks/rtf/rtfml.py
index 97fa175d1a..f3febb1743 100644
--- a/src/calibre/ebooks/rtf/rtfml.py
+++ b/src/calibre/ebooks/rtf/rtfml.py
@@ -15,7 +15,6 @@
from lxml import etree
from calibre.ebooks.metadata import authors_to_string
-from calibre.utils.filenames import ascii_text
from calibre.utils.magick.draw import save_cover_data_to, identify_data
TAGS = {
@@ -79,8 +78,7 @@ def txt2rtf(text):
elif val <= 127:
buf.write(x)
else:
- repl = ascii_text(x)
- c = r'\uc{2}\u{0:d}{1}'.format(val, repl, len(repl))
+ c = r'\u{0:d}?'.format(val)
buf.write(c)
return buf.getvalue()
diff --git a/src/calibre/gui2/actions/choose_library.py b/src/calibre/gui2/actions/choose_library.py
index 4b262ad9dd..f6b19fc4aa 100644
--- a/src/calibre/gui2/actions/choose_library.py
+++ b/src/calibre/gui2/actions/choose_library.py
@@ -246,7 +246,7 @@ def rename_requested(self, name, location):
def delete_requested(self, name, location):
loc = location.replace('/', os.sep)
if not question_dialog(self.gui, _('Are you sure?'), '
'+
- _('All files from %s will be '
+ _('All files from
%s
will be '
'permanently deleted. Are you sure?') % loc,
show_copy_button=False):
return
diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py
index edc274c9b2..732d74b77d 100755
--- a/src/calibre/gui2/dialogs/tweak_epub.py
+++ b/src/calibre/gui2/dialogs/tweak_epub.py
@@ -7,16 +7,16 @@
__docformat__ = 'restructuredtext en'
import os, shutil
-from contextlib import closing
from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED
from PyQt4.Qt import QDialog
from calibre.constants import isosx
-from calibre.gui2 import open_local_file
+from calibre.gui2 import open_local_file, error_dialog
from calibre.gui2.dialogs.tweak_epub_ui import Ui_Dialog
from calibre.libunzip import extract as zipextract
-from calibre.ptempfile import PersistentTemporaryDirectory
+from calibre.ptempfile import (PersistentTemporaryDirectory,
+ PersistentTemporaryFile)
class TweakEpub(QDialog, Ui_Dialog):
'''
@@ -37,11 +37,15 @@ def __init__(self, parent, epub):
self.cancel_button.clicked.connect(self.reject)
self.explode_button.clicked.connect(self.explode)
self.rebuild_button.clicked.connect(self.rebuild)
+ self.preview_button.clicked.connect(self.preview)
# Position update dialog overlaying top left of app window
parent_loc = parent.pos()
self.move(parent_loc.x(),parent_loc.y())
+ self.gui = parent
+ self._preview_files = []
+
def cleanup(self):
if isosx:
try:
@@ -55,6 +59,11 @@ def cleanup(self):
# Delete directory containing exploded ePub
if self._exploded is not None:
shutil.rmtree(self._exploded, ignore_errors=True)
+ for x in self._preview_files:
+ try:
+ os.remove(x)
+ except:
+ pass
def display_exploded(self):
'''
@@ -71,9 +80,8 @@ def explode(self, *args):
self.rebuild_button.setEnabled(True)
self.explode_button.setEnabled(False)
- def rebuild(self, *args):
- self._output = os.path.join(self._exploded, 'rebuilt.epub')
- with closing(ZipFile(self._output, 'w', compression=ZIP_DEFLATED)) as zf:
+ def do_rebuild(self, src):
+ with ZipFile(src, 'w', compression=ZIP_DEFLATED) as zf:
# Write mimetype
zf.write(os.path.join(self._exploded,'mimetype'), 'mimetype', compress_type=ZIP_STORED)
# Write everything else
@@ -86,5 +94,23 @@ def rebuild(self, *args):
zfn = os.path.relpath(absfn,
self._exploded).replace(os.sep, '/')
zf.write(absfn, zfn)
+
+ def preview(self):
+ if not self._exploded:
+ return error_dialog(self, _('Cannot preview'),
+ _('You must first explode the epub before previewing.'),
+ show=True)
+
+ tf = PersistentTemporaryFile('.epub')
+ tf.close()
+ self._preview_files.append(tf.name)
+
+ self.do_rebuild(tf.name)
+
+ self.gui.iactions['View']._view_file(tf.name)
+
+ def rebuild(self, *args):
+ self._output = os.path.join(self._exploded, 'rebuilt.epub')
+ self.do_rebuild(self._output)
return QDialog.accept(self)
diff --git a/src/calibre/gui2/dialogs/tweak_epub.ui b/src/calibre/gui2/dialogs/tweak_epub.ui
index fc6f24675f..a59af4fde1 100644
--- a/src/calibre/gui2/dialogs/tweak_epub.ui
+++ b/src/calibre/gui2/dialogs/tweak_epub.ui
@@ -23,6 +23,16 @@
false
+ -
+
+
+ <p>Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, then 'Open with...' your editor of choice. When tweaks are complete, close the file browser window <b>and the editor windows you used to edit files in the epub</b>.</p><p>Rebuild the ePub, updating your calibre library.</p>
+
+
+ true
+
+
+
-
@@ -37,23 +47,6 @@
- -
-
-
- false
-
-
- Rebuild ePub from exploded contents
-
-
- &Rebuild ePub
-
-
-
- :/images/exec.png:/images/exec.png
-
-
-
-
@@ -68,13 +61,31 @@
- -
-
-
- <p>Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, then 'Open with...' your editor of choice. When tweaks are complete, close the file browser window <b>and the editor windows you used to edit files in the epub</b>.</p><p>Rebuild the ePub, updating your calibre library.</p>
+
-
+
+
+ false
-
- true
+
+ Rebuild ePub from exploded contents
+
+
+ &Rebuild ePub
+
+
+
+ :/images/exec.png:/images/exec.png
+
+
+
+ -
+
+
+ &Preview ePub
+
+
+
+ :/images/view.png:/images/view.png
diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py
index b5cc0163ed..b3c9bd3a02 100644
--- a/src/calibre/gui2/layout.py
+++ b/src/calibre/gui2/layout.py
@@ -44,18 +44,19 @@ def ac(name, text, icon, tooltip):
receiver = partial(self._location_selected, name)
ac.triggered.connect(receiver)
self.tooltips[name] = tooltip
+
+ m = QMenu(parent)
+ self._mem.append(m)
+ a = m.addAction(icon, tooltip)
+ a.triggered.connect(receiver)
if name != 'library':
- m = QMenu(parent)
- self._mem.append(m)
- a = m.addAction(icon, tooltip)
- a.triggered.connect(receiver)
self._mem.append(a)
a = m.addAction(QIcon(I('eject.png')), _('Eject this device'))
a.triggered.connect(self._eject_requested)
- ac.setMenu(m)
self._mem.append(a)
else:
ac.setToolTip(tooltip)
+ ac.setMenu(m)
ac.calibre_name = name
return ac
@@ -71,7 +72,12 @@ def ac(name, text, icon, tooltip):
def set_switch_actions(self, quick_actions, rename_actions, delete_actions,
switch_actions, choose_action):
- self.switch_menu = QMenu()
+ self.switch_menu = self.library_action.menu()
+ if self.switch_menu:
+ self.switch_menu.addSeparator()
+ else:
+ self.switch_menu = QMenu()
+
self.switch_menu.addAction(choose_action)
self.cs_menus = []
for t, acs in [(_('Quick switch'), quick_actions),
@@ -85,7 +91,9 @@ def set_switch_actions(self, quick_actions, rename_actions, delete_actions,
self.switch_menu.addSeparator()
for ac in switch_actions:
self.switch_menu.addAction(ac)
- self.library_action.setMenu(self.switch_menu)
+
+ if self.switch_menu != self.library_action.menu():
+ self.library_action.setMenu(self.switch_menu)
def _location_selected(self, location, *args):
if location != self.current_location and hasattr(self,
diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py
index 26f6788a75..1cfb04921d 100644
--- a/src/calibre/gui2/library/views.py
+++ b/src/calibre/gui2/library/views.py
@@ -439,10 +439,16 @@ def restore_state(self):
if tweaks['sort_columns_at_startup'] is not None:
sh = []
- for c,d in tweaks['sort_columns_at_startup']:
- if not isinstance(d, bool):
- d = True if d == 0 else False
- sh.append((c, d))
+ try:
+ for c,d in tweaks['sort_columns_at_startup']:
+ if not isinstance(d, bool):
+ d = True if d == 0 else False
+ sh.append((c, d))
+ except:
+ # Ignore invalid tweak values as users seem to often get them
+ # wrong
+ import traceback
+ traceback.print_exc()
old_state['sort_history'] = sh
self.apply_state(old_state)
diff --git a/src/calibre/gui2/preferences/metadata_sources.py b/src/calibre/gui2/preferences/metadata_sources.py
index f487051d07..05ff23987d 100644
--- a/src/calibre/gui2/preferences/metadata_sources.py
+++ b/src/calibre/gui2/preferences/metadata_sources.py
@@ -190,7 +190,15 @@ def flags(self, index):
return ans | Qt.ItemIsUserCheckable
def restore_defaults(self):
- self.overrides = dict([(f, self.state(f, True)) for f in self.fields])
+ self.overrides = dict([(f, self.state(f, Qt.Checked)) for f in self.fields])
+ self.reset()
+
+ def select_all(self):
+ self.overrides = dict([(f, Qt.Checked) for f in self.fields])
+ self.reset()
+
+ def clear_all(self):
+ self.overrides = dict([(f, Qt.Unchecked) for f in self.fields])
self.reset()
def setData(self, index, val, role):
@@ -273,6 +281,9 @@ def genesis(self, gui):
self.fields_view.setModel(self.fields_model)
self.fields_model.dataChanged.connect(self.changed_signal)
+ self.select_all_button.clicked.connect(self.fields_model.select_all)
+ self.clear_all_button.clicked.connect(self.fields_model.clear_all)
+
def configure_plugin(self):
for index in self.sources_view.selectionModel().selectedRows():
plugin = self.sources_model.data(index, Qt.UserRole)
diff --git a/src/calibre/gui2/preferences/metadata_sources.ui b/src/calibre/gui2/preferences/metadata_sources.ui
index e46069b036..ff161654dd 100644
--- a/src/calibre/gui2/preferences/metadata_sources.ui
+++ b/src/calibre/gui2/preferences/metadata_sources.ui
@@ -77,8 +77,8 @@
Downloaded metadata fields
-
- -
+
+
-
If you uncheck any fields, metadata for those fields will not be downloaded
@@ -88,6 +88,20 @@
+ -
+
+
+ &Select all
+
+
+
+ -
+
+
+ &Clear all
+
+
+
diff --git a/src/calibre/gui2/store/search/search.py b/src/calibre/gui2/store/search/search.py
index 5654df8ffc..07d4afca54 100644
--- a/src/calibre/gui2/store/search/search.py
+++ b/src/calibre/gui2/store/search/search.py
@@ -155,6 +155,7 @@ def save_state(self):
self.config['results_view_column_width'] = [self.results_view.columnWidth(i) for i in range(self.results_view.model().columnCount())]
self.config['sort_col'] = self.results_view.model().sort_col
self.config['sort_order'] = self.results_view.model().sort_order
+ self.config['open_external'] = self.open_external.isChecked()
store_check = {}
for n in self.store_plugins:
@@ -179,6 +180,8 @@ def restore_state(self):
else:
self.resize_columns()
+ self.open_external.setChecked(self.config.get('open_external', False))
+
store_check = self.config.get('store_checked', None)
if store_check:
for n in store_check:
@@ -212,7 +215,7 @@ def get_results(self):
def open_store(self, index):
result = self.results_view.model().get_result(index)
- self.store_plugins[result.store_name].open(self, result.detail_item)
+ self.store_plugins[result.store_name].open(self, result.detail_item, self.open_external.isChecked())
def check_progress(self):
if not self.search_pool.threads_running() and not self.results_view.model().cover_pool.threads_running() and not self.results_view.model().details_pool.threads_running():
diff --git a/src/calibre/gui2/store/search/search.ui b/src/calibre/gui2/store/search/search.ui
index 0d39a70a29..fe5aaceda4 100644
--- a/src/calibre/gui2/store/search/search.ui
+++ b/src/calibre/gui2/store/search/search.ui
@@ -70,7 +70,7 @@
0
0
215
- 116
+ 93
@@ -101,6 +101,16 @@
+ -
+
+
+ Open a selected book in the system's web browser
+
+
+ Open in &external browser
+
+
+
diff --git a/src/odf/odf2xhtml.py b/src/odf/odf2xhtml.py
index 26da9d9905..a04aa48bf7 100644
--- a/src/odf/odf2xhtml.py
+++ b/src/odf/odf2xhtml.py
@@ -841,11 +841,19 @@ def generate_stylesheet(self):
self.styledict[name] = styles
# Write the styles to HTML
self.writeout(self.default_styles)
+ # Changed by Kovid to not write out endless copies of the same style
+ css_styles = {}
for name in self.stylestack:
styles = self.styledict.get(name)
- css2 = self.cs.convert_styles(styles)
- self.writeout("%s {\n" % name)
- for style, val in css2.items():
+ css2 = tuple(self.cs.convert_styles(styles).iteritems())
+ if css2 in css_styles:
+ css_styles[css2].append(name)
+ else:
+ css_styles[css2] = [name]
+
+ for css2, names in css_styles.iteritems():
+ self.writeout("%s {\n" % ', '.join(names))
+ for style, val in css2:
self.writeout("\t%s: %s;\n" % (style, val) )
self.writeout("}\n")