mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
commit
b25f94275c
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
- title: "Book details panel: Clicking an author name now searches Goodreads by default instead of Wikipedia. Can be changed in Preferences->Interface->Look & feel->Book details"
|
- title: "Book details panel: Clicking an author name now searches Goodreads by default instead of Wikipedia. Can be changed in Preferences->Interface->Look & feel->Book details"
|
||||||
|
|
||||||
- title: "Kobo driver: Add support for the Kobo Auro H2O Edition 2"
|
- title: "Kobo driver: Add support for the Kobo Aura H2O Edition 2"
|
||||||
|
|
||||||
bug fixes:
|
bug fixes:
|
||||||
- title: "PDF output: Fix a regression in the previous release that broke conversion to PDF for some files"
|
- title: "PDF output: Fix a regression in the previous release that broke conversion to PDF for some files"
|
||||||
@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
- title: "Add API to pre-process image data in recipes easily"
|
- title: "Add API to pre-process image data in recipes easily"
|
||||||
|
|
||||||
- title: "Fetch e-book metadata: add option to use only a single metadata plugin"
|
- title: "fetch-ebook-metadata.exe: add option to use only a single metadata plugin"
|
||||||
|
|
||||||
bug fixes:
|
bug fixes:
|
||||||
- title: "E-book viewer: Fix a regression in the previous release that broke printing from inside the viewer"
|
- title: "E-book viewer: Fix a regression in the previous release that broke printing from inside the viewer"
|
||||||
@ -152,7 +152,7 @@
|
|||||||
- title: "PDF output: Fix a regression that broke PDF output for documents containing mathematics"
|
- title: "PDF output: Fix a regression that broke PDF output for documents containing mathematics"
|
||||||
tickets: [1673983]
|
tickets: [1673983]
|
||||||
|
|
||||||
- title: "E-book viewer: Fix a regression that broke the Clear recently read books' action in the viewer"
|
- title: 'E-book viewer: Fix a regression that broke the "Clear recently read books" action in the viewer'
|
||||||
|
|
||||||
improved recipes:
|
improved recipes:
|
||||||
- Go Comics
|
- Go Comics
|
||||||
@ -463,7 +463,7 @@
|
|||||||
|
|
||||||
- title: "Add support for new Kobo firmware version 4.2"
|
- title: "Add support for new Kobo firmware version 4.2"
|
||||||
|
|
||||||
- title: "Allow using Amazon_in, Amazon_au, Amazon_com identifiers in the Book details panel"
|
- title: "Allow using amazon_in, amazon_au, amazon_com identifiers in the Book details panel"
|
||||||
tickets: [1649371]
|
tickets: [1649371]
|
||||||
|
|
||||||
bug fixes:
|
bug fixes:
|
||||||
@ -477,7 +477,7 @@
|
|||||||
- title: "Edit book: Fix the 'Search ignoring markup tool' not ignoring comments/processing instructions, etc"
|
- title: "Edit book: Fix the 'Search ignoring markup tool' not ignoring comments/processing instructions, etc"
|
||||||
tickets: [1651160]
|
tickets: [1651160]
|
||||||
|
|
||||||
- title: "CSS Transforms: Fix 'is'/'is not' rules not matching current color"
|
- title: "CSS Transforms: Fix 'is'/'is not' rules not matching 'currentColor'"
|
||||||
tickets: [1650930]
|
tickets: [1650930]
|
||||||
|
|
||||||
- title: "E-book viewer: Make the swipe up gesture move to next section instead of previous section"
|
- title: "E-book viewer: Make the swipe up gesture move to next section instead of previous section"
|
||||||
|
@ -231,7 +231,8 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
re.compile('commentCount'),
|
re.compile('commentCount'),
|
||||||
'lede-container',
|
'lede-container',
|
||||||
'credit',
|
'credit',
|
||||||
'caption-video'
|
'caption-video',
|
||||||
|
'upshot-social'
|
||||||
]}),
|
]}),
|
||||||
dict(
|
dict(
|
||||||
attrs={'class': lambda x: x and 'related-coverage-marginalia' in x.split()}),
|
attrs={'class': lambda x: x and 'related-coverage-marginalia' in x.split()}),
|
||||||
|
@ -231,7 +231,8 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
re.compile('commentCount'),
|
re.compile('commentCount'),
|
||||||
'lede-container',
|
'lede-container',
|
||||||
'credit',
|
'credit',
|
||||||
'caption-video'
|
'caption-video',
|
||||||
|
'upshot-social'
|
||||||
]}),
|
]}),
|
||||||
dict(
|
dict(
|
||||||
attrs={'class': lambda x: x and 'related-coverage-marginalia' in x.split()}),
|
attrs={'class': lambda x: x and 'related-coverage-marginalia' in x.split()}),
|
||||||
|
@ -20,6 +20,7 @@ from calibre.utils.localization import canonicalize_lang
|
|||||||
readonly = False
|
readonly = False
|
||||||
version = 0 # change this if you change signature of implementation()
|
version = 0 # change this if you change signature of implementation()
|
||||||
|
|
||||||
|
|
||||||
def to_stream(data):
|
def to_stream(data):
|
||||||
ans = BytesIO(data[1])
|
ans = BytesIO(data[1])
|
||||||
ans.name = data[0]
|
ans.name = data[0]
|
||||||
|
@ -25,6 +25,7 @@ from calibre.utils.localization import calibre_langcode_to_name
|
|||||||
def bool_sort_key(bools_are_tristate):
|
def bool_sort_key(bools_are_tristate):
|
||||||
return (lambda x:{True: 1, False: 2, None: 3}.get(x, 3)) if bools_are_tristate else lambda x:{True: 1, False: 2, None: 2}.get(x, 2)
|
return (lambda x:{True: 1, False: 2, None: 3}.get(x, 3)) if bools_are_tristate else lambda x:{True: 1, False: 2, None: 2}.get(x, 2)
|
||||||
|
|
||||||
|
|
||||||
IDENTITY = lambda x: x
|
IDENTITY = lambda x: x
|
||||||
|
|
||||||
|
|
||||||
@ -756,4 +757,3 @@ def create_field(name, table, bools_are_tristate, get_template_functions):
|
|||||||
elif table.metadata['datatype'] == 'series':
|
elif table.metadata['datatype'] == 'series':
|
||||||
cls = SeriesField
|
cls = SeriesField
|
||||||
return cls(name, table, bools_are_tristate, get_template_functions)
|
return cls(name, table, bools_are_tristate, get_template_functions)
|
||||||
|
|
||||||
|
@ -1451,15 +1451,15 @@ class KOBOTOUCH(KOBO):
|
|||||||
|
|
||||||
def open_linux(self):
|
def open_linux(self):
|
||||||
super(KOBOTOUCH, self).open_linux()
|
super(KOBOTOUCH, self).open_linux()
|
||||||
|
|
||||||
self.swap_drives_if_needed()
|
self.swap_drives_if_needed()
|
||||||
|
|
||||||
def open_osx(self):
|
def open_osx(self):
|
||||||
# Just dump some info to the logs.
|
# Just dump some info to the logs.
|
||||||
super(KOBOTOUCH, self).open_osx()
|
super(KOBOTOUCH, self).open_osx()
|
||||||
|
|
||||||
# Wrap some debugging output in a try/except so that it unlikely to break things completely.
|
# Wrap some debugging output in a try/except so that it unlikely to break things completely.
|
||||||
try:
|
try:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
from calibre.constants import plugins
|
from calibre.constants import plugins
|
||||||
usbobserver, usbobserver_err = plugins['usbobserver']
|
usbobserver, usbobserver_err = plugins['usbobserver']
|
||||||
|
@ -201,6 +201,23 @@ class SearchBar(QFrame): # {{{
|
|||||||
self.vl_sep.setFrameStyle(QFrame.VLine | QFrame.Sunken)
|
self.vl_sep.setFrameStyle(QFrame.VLine | QFrame.Sunken)
|
||||||
l.addWidget(self.vl_sep)
|
l.addWidget(self.vl_sep)
|
||||||
|
|
||||||
|
parent.sort_sep = QFrame(self)
|
||||||
|
parent.sort_sep.setFrameStyle(QFrame.VLine | QFrame.Sunken)
|
||||||
|
parent.sort_sep.setVisible(False)
|
||||||
|
parent.sort_button = self.sort_button = sb = QToolButton(self)
|
||||||
|
sb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||||||
|
sb.setToolTip(_('Change how the displayed books are sorted'))
|
||||||
|
sb.setCursor(Qt.PointingHandCursor)
|
||||||
|
sb.setPopupMode(QToolButton.InstantPopup)
|
||||||
|
sb.setAutoRaise(True)
|
||||||
|
sb.setText(_('Sort'))
|
||||||
|
sb.setIcon(QIcon(I('sort.png')))
|
||||||
|
sb.setMenu(QMenu())
|
||||||
|
sb.menu().aboutToShow.connect(self.populate_sort_menu)
|
||||||
|
sb.setVisible(False)
|
||||||
|
l.addWidget(sb)
|
||||||
|
l.addWidget(parent.sort_sep)
|
||||||
|
|
||||||
x = parent.search = SearchBox2(self)
|
x = parent.search = SearchBox2(self)
|
||||||
x.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
x.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||||
x.setObjectName("search")
|
x.setObjectName("search")
|
||||||
@ -230,6 +247,10 @@ class SearchBar(QFrame): # {{{
|
|||||||
_('Do Quick Search (you can also press the Enter key)'))
|
_('Do Quick Search (you can also press the Enter key)'))
|
||||||
|
|
||||||
x = parent.highlight_only_button = QToolButton(self)
|
x = parent.highlight_only_button = QToolButton(self)
|
||||||
|
x.setAutoRaise(True)
|
||||||
|
x.setText(_('Highlight'))
|
||||||
|
x.setCursor(Qt.PointingHandCursor)
|
||||||
|
x.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||||||
x.setIcon(QIcon(I('arrow-down.png')))
|
x.setIcon(QIcon(I('arrow-down.png')))
|
||||||
l.addWidget(x)
|
l.addWidget(x)
|
||||||
|
|
||||||
@ -270,23 +291,6 @@ class SearchBar(QFrame): # {{{
|
|||||||
l.addWidget(x)
|
l.addWidget(x)
|
||||||
x.setVisible(not tweaks['show_saved_search_box'])
|
x.setVisible(not tweaks['show_saved_search_box'])
|
||||||
|
|
||||||
parent.sort_sep = QFrame(self)
|
|
||||||
parent.sort_sep.setFrameStyle(QFrame.VLine | QFrame.Sunken)
|
|
||||||
parent.sort_sep.setVisible(False)
|
|
||||||
l.addWidget(parent.sort_sep)
|
|
||||||
parent.sort_button = self.sort_button = sb = QToolButton(self)
|
|
||||||
sb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
|
||||||
sb.setToolTip(_('Change how the displayed books are sorted'))
|
|
||||||
sb.setCursor(Qt.PointingHandCursor)
|
|
||||||
sb.setPopupMode(QToolButton.InstantPopup)
|
|
||||||
sb.setAutoRaise(True)
|
|
||||||
sb.setText(_('Sort'))
|
|
||||||
sb.setIcon(QIcon(I('sort.png')))
|
|
||||||
sb.setMenu(QMenu())
|
|
||||||
sb.menu().aboutToShow.connect(self.populate_sort_menu)
|
|
||||||
sb.setVisible(False)
|
|
||||||
l.addWidget(sb)
|
|
||||||
|
|
||||||
def populate_sort_menu(self):
|
def populate_sort_menu(self):
|
||||||
from calibre.gui2.ui import get_gui
|
from calibre.gui2.ui import get_gui
|
||||||
get_gui().iactions['Sort By'].update_menu(self.sort_button.menu())
|
get_gui().iactions['Sort By'].update_menu(self.sort_button.menu())
|
||||||
|
@ -492,10 +492,13 @@ class SearchBoxMixin(object): # {{{
|
|||||||
self.focus_to_library()
|
self.focus_to_library()
|
||||||
|
|
||||||
def set_highlight_only_button_icon(self):
|
def set_highlight_only_button_icon(self):
|
||||||
|
b = self.highlight_only_button
|
||||||
if config['highlight_search_matches']:
|
if config['highlight_search_matches']:
|
||||||
self.highlight_only_button.setIcon(QIcon(I('highlight_only_on.png')))
|
b.setIcon(QIcon(I('highlight_only_on.png')))
|
||||||
|
b.setText(_('Filter'))
|
||||||
else:
|
else:
|
||||||
self.highlight_only_button.setIcon(QIcon(I('highlight_only_off.png')))
|
b.setIcon(QIcon(I('highlight_only_off.png')))
|
||||||
|
b.setText(_('Highlight'))
|
||||||
self.highlight_only_button.setVisible(gprefs['show_highlight_toggle_button'])
|
self.highlight_only_button.setVisible(gprefs['show_highlight_toggle_button'])
|
||||||
self.library_view.model().set_highlight_only(config['highlight_search_matches'])
|
self.library_view.model().set_highlight_only(config['highlight_search_matches'])
|
||||||
|
|
||||||
|
@ -341,6 +341,22 @@ class TagBrowserMixin(object): # {{{
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
class FindBox(HistoryLineEdit): # {{{
|
||||||
|
|
||||||
|
def keyPressEvent(self, event):
|
||||||
|
k = event.key()
|
||||||
|
if k not in (Qt.Key_Up, Qt.Key_Down):
|
||||||
|
return HistoryLineEdit.keyPressEvent(self, event)
|
||||||
|
self.blockSignals(True)
|
||||||
|
if k == Qt.Key_Down and self.currentIndex() == 0 and not self.lineEdit().text():
|
||||||
|
self.setCurrentIndex(1), self.setCurrentIndex(0)
|
||||||
|
event.accept()
|
||||||
|
else:
|
||||||
|
HistoryLineEdit.keyPressEvent(self, event)
|
||||||
|
self.blockSignals(False)
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
class TagBrowserBar(QWidget): # {{{
|
class TagBrowserBar(QWidget): # {{{
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
@ -365,7 +381,7 @@ class TagBrowserBar(QWidget): # {{{
|
|||||||
self.label = la = QLabel(self)
|
self.label = la = QLabel(self)
|
||||||
la.setText(_('Tag browser'))
|
la.setText(_('Tag browser'))
|
||||||
|
|
||||||
self.item_search = HistoryLineEdit(parent)
|
self.item_search = FindBox(parent)
|
||||||
self.item_search.setMinimumContentsLength(5)
|
self.item_search.setMinimumContentsLength(5)
|
||||||
self.item_search.setSizeAdjustPolicy(self.item_search.AdjustToMinimumContentsLengthWithIcon)
|
self.item_search.setSizeAdjustPolicy(self.item_search.AdjustToMinimumContentsLengthWithIcon)
|
||||||
self.item_search.initialize('tag_browser_search')
|
self.item_search.initialize('tag_browser_search')
|
||||||
@ -380,26 +396,24 @@ class TagBrowserBar(QWidget): # {{{
|
|||||||
ac = QAction(parent)
|
ac = QAction(parent)
|
||||||
parent.addAction(ac)
|
parent.addAction(ac)
|
||||||
parent.keyboard.register_shortcut('tag browser find box',
|
parent.keyboard.register_shortcut('tag browser find box',
|
||||||
_('Find item'), default_keys=(),
|
_('Find next match'), default_keys=(),
|
||||||
action=ac, group=_('Tag browser'))
|
action=ac, group=_('Tag browser'))
|
||||||
ac.triggered.connect(self.set_focus_to_find_box)
|
ac.triggered.connect(self.set_focus_to_find_box)
|
||||||
|
|
||||||
self.search_button = QToolButton()
|
self.search_button = QToolButton()
|
||||||
self.search_button.setCursor(Qt.PointingHandCursor)
|
self.search_button.setCursor(Qt.PointingHandCursor)
|
||||||
self.search_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
|
||||||
self.search_button.setIcon(QIcon(I('search.png')))
|
self.search_button.setIcon(QIcon(I('search.png')))
|
||||||
self.search_button.setText(_('Find'))
|
|
||||||
self.search_button.setToolTip(_('Find the first/next matching item'))
|
self.search_button.setToolTip(_('Find the first/next matching item'))
|
||||||
ac = QAction(parent)
|
ac = QAction(parent)
|
||||||
parent.addAction(ac)
|
parent.addAction(ac)
|
||||||
parent.keyboard.register_shortcut('tag browser find button',
|
parent.keyboard.register_shortcut('tag browser find button',
|
||||||
_('Find button'), default_keys=(),
|
_('Find in Tag browser'), default_keys=(),
|
||||||
action=ac, group=_('Tag browser'))
|
action=ac, group=_('Tag browser'))
|
||||||
ac.triggered.connect(self.search_button.click)
|
ac.triggered.connect(self.search_button.click)
|
||||||
|
|
||||||
self.toggle_search_button = b = QToolButton(self)
|
self.toggle_search_button = b = QToolButton(self)
|
||||||
le = self.item_search.lineEdit()
|
le = self.item_search.lineEdit()
|
||||||
le.addAction(QIcon(I('window-close.png')), le.LeadingPosition).triggered.connect(self.toggle_search_button.click)
|
le.addAction(QIcon(I('window-close.png')), le.LeadingPosition).triggered.connect(self.close_find_box)
|
||||||
b.setCursor(Qt.PointingHandCursor)
|
b.setCursor(Qt.PointingHandCursor)
|
||||||
b.setIcon(QIcon(I('search.png')))
|
b.setIcon(QIcon(I('search.png')))
|
||||||
b.setCheckable(True)
|
b.setCheckable(True)
|
||||||
@ -409,6 +423,11 @@ class TagBrowserBar(QWidget): # {{{
|
|||||||
b.toggled.connect(self.update_searchbar_state)
|
b.toggled.connect(self.update_searchbar_state)
|
||||||
self.update_searchbar_state()
|
self.update_searchbar_state()
|
||||||
|
|
||||||
|
def close_find_box(self):
|
||||||
|
self.item_search.setCurrentIndex(0)
|
||||||
|
self.item_search.setCurrentText('')
|
||||||
|
self.toggle_search_button.click()
|
||||||
|
|
||||||
def set_focus_to_find_box(self):
|
def set_focus_to_find_box(self):
|
||||||
self.toggle_search_button.setChecked(True)
|
self.toggle_search_button.setChecked(True)
|
||||||
self.item_search.setFocus()
|
self.item_search.setFocus()
|
||||||
@ -489,7 +508,7 @@ class TagBrowserWidget(QWidget): # {{{
|
|||||||
ac = QAction(parent)
|
ac = QAction(parent)
|
||||||
parent.addAction(ac)
|
parent.addAction(ac)
|
||||||
parent.keyboard.register_shortcut('tag browser alter',
|
parent.keyboard.register_shortcut('tag browser alter',
|
||||||
_('Alter Tag browser'), default_keys=(),
|
_('Change Tag browser'), default_keys=(),
|
||||||
action=ac, group=_('Tag browser'))
|
action=ac, group=_('Tag browser'))
|
||||||
ac.triggered.connect(l.showMenu)
|
ac.triggered.connect(l.showMenu)
|
||||||
|
|
||||||
|
@ -12,8 +12,7 @@ import re, string, traceback
|
|||||||
|
|
||||||
from calibre import prints
|
from calibre import prints
|
||||||
from calibre.constants import DEBUG
|
from calibre.constants import DEBUG
|
||||||
from calibre.utils.formatter_functions import formatter_functions, compile_user_function
|
from calibre.utils.formatter_functions import formatter_functions
|
||||||
from calibre.utils.config import tweaks
|
|
||||||
|
|
||||||
|
|
||||||
class _Parser(object):
|
class _Parser(object):
|
||||||
@ -174,6 +173,7 @@ class _Parser(object):
|
|||||||
else:
|
else:
|
||||||
self.error(_('expression is not function or constant'))
|
self.error(_('expression is not function or constant'))
|
||||||
|
|
||||||
|
|
||||||
class TemplateFormatter(string.Formatter):
|
class TemplateFormatter(string.Formatter):
|
||||||
'''
|
'''
|
||||||
Provides a format function that substitutes '' for any missing value
|
Provides a format function that substitutes '' for any missing value
|
||||||
|
@ -1635,6 +1635,7 @@ class UserFunction(FormatterUserFunction):
|
|||||||
cls = locals_['UserFunction'](name, doc, arg_count, eval_func)
|
cls = locals_['UserFunction'](name, doc, arg_count, eval_func)
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
|
||||||
def compile_user_template_functions(funcs):
|
def compile_user_template_functions(funcs):
|
||||||
compiled_funcs = {}
|
compiled_funcs = {}
|
||||||
for func in funcs:
|
for func in funcs:
|
||||||
@ -1653,6 +1654,7 @@ def compile_user_template_functions(funcs):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return compiled_funcs
|
return compiled_funcs
|
||||||
|
|
||||||
|
|
||||||
def load_user_template_functions(library_uuid, funcs, precompiled_user_functions=None):
|
def load_user_template_functions(library_uuid, funcs, precompiled_user_functions=None):
|
||||||
unload_user_template_functions(library_uuid)
|
unload_user_template_functions(library_uuid)
|
||||||
if precompiled_user_functions:
|
if precompiled_user_functions:
|
||||||
@ -1661,5 +1663,6 @@ def load_user_template_functions(library_uuid, funcs, precompiled_user_functions
|
|||||||
compiled_funcs = compile_user_template_functions(funcs)
|
compiled_funcs = compile_user_template_functions(funcs)
|
||||||
formatter_functions().register_functions(library_uuid, compiled_funcs.values())
|
formatter_functions().register_functions(library_uuid, compiled_funcs.values())
|
||||||
|
|
||||||
|
|
||||||
def unload_user_template_functions(library_uuid):
|
def unload_user_template_functions(library_uuid):
|
||||||
formatter_functions().unregister_functions(library_uuid)
|
formatter_functions().unregister_functions(library_uuid)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user