diff --git a/imgsrc/rating.svg b/imgsrc/rating.svg new file mode 100644 index 0000000000..d289c71b99 --- /dev/null +++ b/imgsrc/rating.svg @@ -0,0 +1,589 @@ + + + diff --git a/resources/content_server/gui.js b/resources/content_server/gui.js index 631fb8b617..d0fb49cc8e 100644 --- a/resources/content_server/gui.js +++ b/resources/content_server/gui.js @@ -26,7 +26,7 @@ var current_library_request = null; ////////////////////////////// GET BOOK LIST ////////////////////////////// -var LIBRARY_FETCH_TIMEOUT = 30000; // milliseconds +var LIBRARY_FETCH_TIMEOUT = 5*60000; // milliseconds function create_table_headers() { var thead = $('table#book_list thead tr'); diff --git a/resources/images/rating.png b/resources/images/rating.png new file mode 100644 index 0000000000..81eba505b9 Binary files /dev/null and b/resources/images/rating.png differ diff --git a/resources/images/star.png b/resources/images/star.png deleted file mode 100644 index 6eb1fb890f..0000000000 Binary files a/resources/images/star.png and /dev/null differ diff --git a/resources/jacket/stylesheet.css b/resources/jacket/stylesheet.css new file mode 100644 index 0000000000..8dee8edc3c --- /dev/null +++ b/resources/jacket/stylesheet.css @@ -0,0 +1,116 @@ +/* +** Book Jacket generation +** +** The template for Book Jackets is template.xhtml +** This CSS is inserted into the generated HTML at conversion time +** +** Users can control parts of the presentation of a generated book jacket by +** editing this file and template.xhtml +** +** The general form of a generated Book Jacket: +** +** Title +** Series: series [series_index] +** Published: year_of_publication +** Rating: #_of_stars +** Tags: tag1, tag2, tag3 ... +** +** Comments +** +** If a book does not have Series information, a date of publication, a rating or tags +** the corresponding row is automatically removed from the generated book jacket. +*/ + +/* +** Banner +** Only affects EPUB, kindle ignores this type of formatting +*/ +.cbj_banner { + background: #eee; + border: thin solid black; + margin: 1em; + padding: 1em; + -webkit-border-radius:8px; + } + +/* +** Title +*/ +.cbj_title { + font-size: x-large; + text-align: center; + } + +/* +** Table containing Series, Publication Year, Rating and Tags +*/ +table.cbj_header { + width: 100%; + } + +/* +** General formatting for banner labels +*/ +table.cbj_header td.cbj_label { + font-family: sans-serif; + font-weight: bold; + text-align: right; + width: 40%; + } + +/* +** General formatting for banner content +*/ +table.cbj_header td.cbj_content { + font-family: sans-serif; + text-align: left; + width:60%; + } + +/* +** To skip a banner item (Series|Published|Rating|Tags), +** edit the appropriate CSS rule below. +*/ +table.cbj_header tr.cbj_series { + /* Uncomment the next line to remove 'Series' from banner section */ + /* display:none; */ + } + +table.cbj_header tr.cbj_pubdate { + /* Uncomment the next line to remove 'Published' from banner section */ + /* display:none; */ + } + +table.cbj_header tr.cbj_rating { + /* Uncomment the next line to remove 'Rating' from banner section */ + /* display:none; */ + } + +table.cbj_header tr.cbj_tags { + /* Uncomment the next line to remove 'Tags' from banner section */ + /* display:none; */ + } + +hr { + /* This rule controls formatting for any hr elements contained in the jacket */ + border-top: 0px solid white; + border-right: 0px solid white; + border-bottom: 2px solid black; + border-left: 0px solid white; + margin-left: 10%; + width: 80%; + } + +.cbj_footer { + font-family: sans-serif; + font-size: small; + margin-top: 8px; + text-align: center; + } +.cbj_smallcaps { + font-size: 90%; + } + +.cbj_comments { + font-family: sans-serif; + } diff --git a/resources/jacket/template.xhtml b/resources/jacket/template.xhtml new file mode 100644 index 0000000000..93e12983e8 --- /dev/null +++ b/resources/jacket/template.xhtml @@ -0,0 +1,34 @@ + +
+%s
' % (m.group(1), m.group(3), m.group(2))) ] - + def parse_index(self): INDEX = 'http://xkcd.com/archive/' - soup = self.index_to_soup(INDEX) + soup = self.index_to_soup(INDEX) articles = [] for item in soup.findAll('a', title=True): articles.append({ 'date': item['title'], 'timestamp': time.mktime(time.strptime(item['title'], '%Y-%m-%d'))+1, 'url': 'http://xkcd.com' + item['href'], - 'title': self.tag_to_string(item).encode('UTF-8'), + 'title': self.tag_to_string(item), 'description': '', 'content': '', }) diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 4c87236e71..68df832048 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -459,7 +459,7 @@ from calibre.devices.iriver.driver import IRIVER_STORY from calibre.devices.binatone.driver import README from calibre.devices.hanvon.driver import N516, EB511, ALEX, AZBOOKA, THEBOOK from calibre.devices.edge.driver import EDGE -from calibre.devices.teclast.driver import TECLAST_K3, NEWSMY, IPAPYRUS +from calibre.devices.teclast.driver import TECLAST_K3, NEWSMY, IPAPYRUS, SOVOS from calibre.devices.sne.driver import SNE from calibre.devices.misc import PALMPRE, AVANT, SWEEX, PDNOVEL, KOGAN, GEMEI from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG @@ -557,6 +557,7 @@ plugins += [ TECLAST_K3, NEWSMY, IPAPYRUS, + SOVOS, EDGE, SNE, ALEX, diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index 1563f764ca..2b5eb5011e 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -248,6 +248,9 @@ class OutputProfile(Plugin): #: If True, the date is appended to the title of downloaded news periodical_date_in_title = True + #: The character used to represent a star in ratings + ratings_char = u'*' + @classmethod def tags_to_string(cls, tags): return escape(', '.join(tags)) @@ -273,6 +276,7 @@ class iPadOutput(OutputProfile): 'macros': {'border-width': '{length}|medium|thick|thin'} } ] + ratings_char = u'\u2605' touchscreen = True # touchscreen_news_css {{{ touchscreen_news_css = u''' @@ -553,10 +557,11 @@ class KindleOutput(OutputProfile): fsizes = [12, 12, 14, 16, 18, 20, 22, 24] supports_mobi_indexing = True periodical_date_in_title = False + ratings_char = u'\u2605' @classmethod def tags_to_string(cls, tags): - return u'%s)', re.DOTALL)
elif format == 'pdf':
linere = re.compile('(?<= \n ' + match.group(1) + '
- (re.compile(r' '),
-
- # Remove hyphenation
- (re.compile(r'- '),
# Clean up spaces
(re.compile(u'(?<=[\.,;\?!”"\'])[\s^ ]*(?=<)'), lambda match: ' '),
- # Connect paragraphs split by -
- (re.compile(u'(?<=[^\s][-–])[\s]*( )*\s*(?=[^\s])'), lambda match: ''),
# Add space before and after italics
(re.compile(u'(?'), lambda match: ' '),
(re.compile(r'(?=\w)'), lambda match: ' '),
@@ -328,12 +329,29 @@ class HTMLPreProcessor(object):
print 'Failed to parse remove_footer regexp'
traceback.print_exc()
+ # unwrap hyphenation - moved here so it's executed after header/footer removal
+ if is_pdftohtml:
+ # unwrap visible dashes and hyphens - don't delete they are often hyphens for
+ # for compound words, formatting, etc
+ end_rules.append((re.compile(u'(?<=[-–—])\s* \s*(?=[[a-z\d])'), lambda match: ''))
+ # unwrap/delete soft hyphens
+ end_rules.append((re.compile(u'[](\s* )+\s*(?=[[a-z\d])'), lambda match: ''))
+ # unwrap/delete soft hyphens with formatting
+ end_rules.append((re.compile(u'[]\s*((i|u|b)>)+(\s* )+\s*(<(i|u|b)>)+\s*(?=[[a-z\d])'), lambda match: ''))
+
+ # Make the more aggressive chapter marking regex optional with the preprocess option to
+ # reduce false positives and move after header/footer removal
+ if getattr(self.extra_opts, 'preprocess_html', None):
+ if is_pdftohtml:
+ end_rules.append((re.compile(r' \s*(?P \s*(?P )?'), chap_head),)
+
if getattr(self.extra_opts, 'unwrap_factor', 0.0) > 0.01:
length = line_length('pdf', html, getattr(self.extra_opts, 'unwrap_factor'))
if length:
+ # print "The pdf line length returned is " + str(length)
end_rules.append(
# Un wrap using punctuation
- (re.compile(r'(?<=.{%i}[a-z\.,;:)\-IA])\s*(?P '
+ else:
+ return ' '+span
+ else:
+ if not span:
+ return ' '
+ else:
+ return ' '+span
+
+ def no_markup(self, raw, percent):
+ '''
+ Detects total marked up line endings in the file. raw is the text to
+ inspect. Percent is the minimum percent of line endings which should
+ be marked up to return true.
+ '''
+ htm_end_ere = re.compile(' [^>]*)>\s*(?P(]*>\s*)+)?\s*(\u00a0){2,}', re.IGNORECASE)
+ html = txtindent.sub(self.insert_indent, html)
+ if self.found_indents > 1:
+ self.log("replaced "+str(self.found_indents)+ " nbsp indents with inline styles")
+ # remove remaining non-breaking spaces
+ html = re.sub(ur'\u00a0', ' ', html)
+ # Get rid of empty )', re.IGNORECASE|re.DOTALL)
+ blankreg = re.compile(r'\s* ]*>\s*(<(b|i|u)>)?\s*((b|i|u)>)?\s* \s*", "\n ", html)
+
+ # some lit files don't have any tags or equivalent (generally just plain text between
+ # ', html)
+
+ # detect chapters/sections to match xpath or splitting logic
+ heading = re.compile(' ]*>', re.IGNORECASE)
+ spans_reg = re.compile(']*>', re.IGNORECASE)
+ paras = len(paras_reg.findall(html))
+ spans = len(spans_reg.findall(html))
+ if spans > 1:
+ if float(paras) / float(spans) < 0.75:
+ format = 'spanned_html'
+ else:
+ format = 'html'
+ else:
+ format = 'html'
+
+ # Calculate Length
+ length = line_length(format, html, 0.4)
+ self.log("*** Median line length is " + str(length) + ",calculated with " + format + " format ***")
+ #
+ # Unwrap and/or delete soft-hyphens, hyphens
+ html = re.sub(u'\s*(\s*([iubp]>\s*<[iubp][^>]*>\s*)?]*>|[iubp]>\s*<[iubp][^>]*>)?\s*', '', html)
+ html = re.sub(u'(?<=[-–—])\s*(?=<)(\s*([iubp]>\s*<[iubp][^>]*>\s*)?]*>|[iubp]>\s*<[iubp][^>]*>)?\s*(?=[[a-z\d])', '', html)
+
+ # Unwrap lines using punctation if the median length of all lines is less than 200
+ unwrap = re.compile(r"(?<=.{%i}[a-z,;:\IA])\s*(span|p|div)>\s*((p|span|div)>)?\s*(?P
).*?(?=
)', re.DOTALL)
+ elif format == 'spanned_html':
+ linere = re.compile('(?<=)', re.DOTALL)
lines = linere.findall(raw)
lengths = []
@@ -219,35 +221,34 @@ class HTMLPreProcessor(object):
(re.compile(u'˛\s*(
|file:////?[A-Z].*
(?=\s*
))', re.IGNORECASE), lambda match: ''),
+
+ # Center separator lines
+ (re.compile(u'
\s*(?P
'), lambda match: '
tags
- (re.compile(r'
'),
- # Replace
with
'),
# Remove gray background
(re.compile(r']+>'), lambda match : ''),
# Detect Chapters to match default XPATH in GUI
- (re.compile(r'(?=<(/?br|p))(<(/?br|p)[^>]*)?>\s*(?P
]*>)\n?((?=()?\s*\w+(\s+\w+)?()?(
]*>|?p[^>]*>))((?P
]*>|?p[^>]*>)))?'), chap_head),
+ (re.compile(r'
\s*(?P
\s*){1,3}\s*(?P
)?', re.IGNORECASE), chap_head),
+ # Cover the case where every letter in a chapter title is separated by a space
+ (re.compile(r'
\s*(?P
\s*){1,3}\s*(?P
))?'), chap_head),
# Have paragraphs show better
(re.compile(r''+chap+'
\n'
+ else:
+ self.html_preprocess_sections = self.html_preprocess_sections + 1
+ self.log("found " + str(self.html_preprocess_sections) + " chapters & titles. - " + str(chap) + ", " + str(title))
+ return ''+chap+'
\n'+title+'
\n'
+
+ def chapter_break(self, match):
+ chap = match.group('section')
+ styles = match.group('styles')
+ self.html_preprocess_sections = self.html_preprocess_sections + 1
+ self.log("marked " + str(self.html_preprocess_sections) + " section markers based on punctuation. - " + str(chap))
+ return '<'+styles+' style="page-break-before:always">'+chap
+
+ def insert_indent(self, match):
+ pstyle = match.group('formatting')
+ span = match.group('span')
+ self.found_indents = self.found_indents + 1
+ if pstyle:
+ if not span:
+ return ' tags), check and mark up line endings if required before proceeding
+ if self.no_markup(html, 0.1):
+ self.log("not enough paragraph markers, adding now")
+ add_markup = re.compile('(?)(\n)')
+ html = add_markup.sub('
'+'
', html)
+
+ return html
diff --git a/src/calibre/ebooks/fb2/output.py b/src/calibre/ebooks/fb2/output.py
index d0125afe89..d6c7a25a90 100644
--- a/src/calibre/ebooks/fb2/output.py
+++ b/src/calibre/ebooks/fb2/output.py
@@ -28,6 +28,9 @@ class FB2Output(OutputFormatPlugin):
])
def convert(self, oeb_book, output_path, input_plugin, opts, log):
+ from calibre.ebooks.oeb.transforms.jacket import linearize_jacket
+ linearize_jacket(oeb_book)
+
fb2mlizer = FB2MLizer(log)
fb2_content = fb2mlizer.extract_content(oeb_book, opts)
diff --git a/src/calibre/ebooks/html/input.py b/src/calibre/ebooks/html/input.py
index d57bfddd3e..084d48e54b 100644
--- a/src/calibre/ebooks/html/input.py
+++ b/src/calibre/ebooks/html/input.py
@@ -24,7 +24,7 @@ from calibre.constants import islinux, isfreebsd, iswindows
from calibre import unicode_path
from calibre.utils.localization import get_lang
from calibre.utils.filenames import ascii_filename
-from calibre.ebooks.conversion.preprocess import line_length
+from calibre.ebooks.conversion.utils import PreProcessor
class Link(object):
'''
@@ -491,20 +491,6 @@ class HTMLInput(InputFormatPlugin):
return (None, raw)
def preprocess_html(self, html):
- if not hasattr(self, 'log'):
- from calibre.utils.logging import default_log
- self.log = default_log
- self.log("********* Preprocessing HTML *********")
- # Detect Chapters to match the xpath in the GUI
- chapdetect = re.compile(r'(?=?(br|p|span))(?(br|p|span)[^>]*>)?\s*(?P'+'\g
\n', html)
- # Unwrap lines using punctation if the median length of all lines is less than 150
- #
- # Insert extra line feeds so the line length regex functions properly
- html = re.sub(r"'+'\g
\n', html)
- # Unwrap lines using punctation if the median length of all lines is less than 150
- #
- # Insert extra line feeds so the line length regex functions properly
- html = re.sub(r"
]*>\s*]*>\s*(?P
]*>\s*(]*>\s*\s*)
\s*){0,3}\s*]*>\s*(]*>)?\s*" % length, re.UNICODE)
- if length < 150:
- res = unwrap.sub(' ', res)
+ preprocessor = PreProcessor(log=getattr(self, 'log', None))
+ res = preprocessor(res)
f.write(res)
self.write_inline_css(inline_class)
stream.seek(0)
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index 1b61404589..e58dce5559 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -50,6 +50,7 @@ gprefs.defaults['action-layout-context-menu-device'] = (
gprefs.defaults['show_splash_screen'] = True
gprefs.defaults['toolbar_icon_size'] = 'medium'
gprefs.defaults['toolbar_text'] = 'auto'
+gprefs.defaults['show_child_bar'] = False
# }}}
diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py
index 57ad900fba..b2d1656367 100644
--- a/src/calibre/gui2/actions/__init__.py
+++ b/src/calibre/gui2/actions/__init__.py
@@ -71,6 +71,12 @@ class InterfaceAction(QObject):
all_locations = frozenset(['toolbar', 'toolbar-device', 'context-menu',
'context-menu-device'])
+ #: Type of action
+ #: 'current' means acts on the current view
+ #: 'global' means an action that does not act on the current view, but rather
+ #: on calibre as a whole
+ action_type = 'global'
+
def __init__(self, parent, site_customization):
QObject.__init__(self, parent)
self.setObjectName(self.name)
diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py
index f0ff794fab..add7bf1d5b 100644
--- a/src/calibre/gui2/actions/add.py
+++ b/src/calibre/gui2/actions/add.py
@@ -25,6 +25,7 @@ class AddAction(InterfaceAction):
action_spec = (_('Add books'), 'add_book.png',
_('Add books to the calibre library/device from files on your computer')
, _('A'))
+ action_type = 'current'
def genesis(self):
self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book)
diff --git a/src/calibre/gui2/actions/add_to_library.py b/src/calibre/gui2/actions/add_to_library.py
index 6fc0d5fb1f..05aea8f1dd 100644
--- a/src/calibre/gui2/actions/add_to_library.py
+++ b/src/calibre/gui2/actions/add_to_library.py
@@ -13,6 +13,7 @@ class AddToLibraryAction(InterfaceAction):
action_spec = (_('Add books to library'), 'add_book.png',
_('Add books to your calibre library from the connected device'), None)
dont_add_to = frozenset(['toolbar', 'context-menu'])
+ action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.add_books_to_library)
diff --git a/src/calibre/gui2/actions/annotate.py b/src/calibre/gui2/actions/annotate.py
index 5356d63e98..dfafcd1a39 100644
--- a/src/calibre/gui2/actions/annotate.py
+++ b/src/calibre/gui2/actions/annotate.py
@@ -18,6 +18,7 @@ class FetchAnnotationsAction(InterfaceAction):
name = 'Fetch Annotations'
action_spec = (_('Fetch annotations (experimental)'), None, None, None)
+ action_type = 'current'
def genesis(self):
pass
diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py
index ee0f06ab71..29acfc52b1 100644
--- a/src/calibre/gui2/actions/convert.py
+++ b/src/calibre/gui2/actions/convert.py
@@ -21,6 +21,7 @@ class ConvertAction(InterfaceAction):
name = 'Convert Books'
action_spec = (_('Convert books'), 'convert.png', None, _('C'))
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
+ action_type = 'current'
def genesis(self):
cm = QMenu()
diff --git a/src/calibre/gui2/actions/copy_to_library.py b/src/calibre/gui2/actions/copy_to_library.py
index 7127c91e8c..6b7654f644 100644
--- a/src/calibre/gui2/actions/copy_to_library.py
+++ b/src/calibre/gui2/actions/copy_to_library.py
@@ -80,6 +80,7 @@ class CopyToLibraryAction(InterfaceAction):
_('Copy selected books to the specified library'), None)
popup_type = QToolButton.InstantPopup
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
+ action_type = 'current'
def genesis(self):
self.menu = QMenu(self.gui)
diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py
index 0343c6df84..406860e4ec 100644
--- a/src/calibre/gui2/actions/delete.py
+++ b/src/calibre/gui2/actions/delete.py
@@ -16,6 +16,7 @@ class DeleteAction(InterfaceAction):
name = 'Remove Books'
action_spec = (_('Remove books'), 'trash.png', None, _('Del'))
+ action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.delete_books)
diff --git a/src/calibre/gui2/actions/edit_collections.py b/src/calibre/gui2/actions/edit_collections.py
index e45d36fc62..7f5dd76538 100644
--- a/src/calibre/gui2/actions/edit_collections.py
+++ b/src/calibre/gui2/actions/edit_collections.py
@@ -13,6 +13,7 @@ class EditCollectionsAction(InterfaceAction):
action_spec = (_('Manage collections'), None,
_('Manage the collections on this device'), None)
dont_add_to = frozenset(['toolbar', 'context-menu'])
+ action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.edit_collections)
diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py
index f0232d9859..ac04652efa 100644
--- a/src/calibre/gui2/actions/edit_metadata.py
+++ b/src/calibre/gui2/actions/edit_metadata.py
@@ -22,6 +22,7 @@ class EditMetadataAction(InterfaceAction):
name = 'Edit Metadata'
action_spec = (_('Edit metadata'), 'edit_input.png', None, _('E'))
+ action_type = 'current'
def genesis(self):
self.create_action(spec=(_('Merge book records'), 'merge_books.png',
@@ -209,8 +210,9 @@ class EditMetadataAction(InterfaceAction):
dest_id, src_books, src_ids = self.books_to_merge(rows)
if safe_merge:
if not confirm(' '+_(
- 'All book formats and metadata from the selected books '
- 'will be added to the first selected book. '+_(
- 'All book formats and metadata from the selected books will be merged '
- 'into the first selected book.
'
+ 'Book formats and metadata from the selected books '
+ 'will be added to the first selected book. '
+ 'ISBN will not be merged.
'
'The second and subsequently selected books will not '
'be deleted or changed.
'
'Please confirm you want to proceed.')
@@ -220,8 +222,9 @@ class EditMetadataAction(InterfaceAction):
self.merge_metadata(dest_id, src_ids)
else:
if not confirm('
'
+ 'Book formats and metadata from the selected books will be merged '
+ 'into the first selected book. '
+ 'ISBN will not be merged.
'
'After merger the second and '
'subsequently selected books will be deleted.
'
'All book formats of the first selected book will be kept '
diff --git a/src/calibre/gui2/actions/open.py b/src/calibre/gui2/actions/open.py
index 106bfa24f6..141ff01a66 100644
--- a/src/calibre/gui2/actions/open.py
+++ b/src/calibre/gui2/actions/open.py
@@ -14,6 +14,7 @@ class OpenFolderAction(InterfaceAction):
action_spec = (_('Open containing folder'), 'document_open.png', None,
_('O'))
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
+ action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.gui.iactions['View'].view_folder)
diff --git a/src/calibre/gui2/actions/save_to_disk.py b/src/calibre/gui2/actions/save_to_disk.py
index bfcc02e130..e9664b9980 100644
--- a/src/calibre/gui2/actions/save_to_disk.py
+++ b/src/calibre/gui2/actions/save_to_disk.py
@@ -38,6 +38,7 @@ class SaveToDiskAction(InterfaceAction):
name = "Save To Disk"
action_spec = (_('Save to disk'), 'save.png', None, _('S'))
+ action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.save_to_disk)
diff --git a/src/calibre/gui2/actions/show_book_details.py b/src/calibre/gui2/actions/show_book_details.py
index d17d0998f1..18b0a694bf 100644
--- a/src/calibre/gui2/actions/show_book_details.py
+++ b/src/calibre/gui2/actions/show_book_details.py
@@ -16,6 +16,7 @@ class ShowBookDetailsAction(InterfaceAction):
action_spec = (_('Show book details'), 'dialog_information.png', None,
_('I'))
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
+ action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.show_book_info)
diff --git a/src/calibre/gui2/actions/similar_books.py b/src/calibre/gui2/actions/similar_books.py
index 1a14869a9c..644cd3160a 100644
--- a/src/calibre/gui2/actions/similar_books.py
+++ b/src/calibre/gui2/actions/similar_books.py
@@ -16,6 +16,7 @@ class SimilarBooksAction(InterfaceAction):
name = 'Similar Books'
action_spec = (_('Similar books...'), None, None, None)
popup_type = QToolButton.InstantPopup
+ action_type = 'current'
def genesis(self):
m = QMenu(self.gui)
diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py
index 2f6be24e5b..0fbf86c567 100644
--- a/src/calibre/gui2/actions/view.py
+++ b/src/calibre/gui2/actions/view.py
@@ -22,6 +22,7 @@ class ViewAction(InterfaceAction):
name = 'View'
action_spec = (_('View'), 'view.png', None, _('V'))
+ action_type = 'current'
def genesis(self):
self.persistent_files = []
diff --git a/src/calibre/gui2/convert/look_and_feel.py b/src/calibre/gui2/convert/look_and_feel.py
index b0403bf1dd..ec3f0b944d 100644
--- a/src/calibre/gui2/convert/look_and_feel.py
+++ b/src/calibre/gui2/convert/look_and_feel.py
@@ -22,7 +22,7 @@ class LookAndFeelWidget(Widget, Ui_Form):
Widget.__init__(self, parent,
['change_justification', 'extra_css', 'base_font_size',
'font_size_mapping', 'line_height',
- 'linearize_tables',
+ 'linearize_tables', 'smarten_punctuation',
'disable_font_rescaling', 'insert_blank_line',
'remove_paragraph_spacing', 'remove_paragraph_spacing_indent_size','input_encoding',
'asciiize', 'keep_ligatures']
diff --git a/src/calibre/gui2/convert/look_and_feel.ui b/src/calibre/gui2/convert/look_and_feel.ui
index de48e7caf9..c683300854 100644
--- a/src/calibre/gui2/convert/look_and_feel.ui
+++ b/src/calibre/gui2/convert/look_and_feel.ui
@@ -178,7 +178,7 @@
- ``, ``
``, ````,
+``