mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge branch 'kovidgoyal:master' into master
This commit is contained in:
commit
5bd70ffc97
@ -25,7 +25,9 @@ class IrishIndependent(BasicNewsRecipe):
|
|||||||
]
|
]
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
|
('Frontpage News', 'http://www.independent.ie/rss'),
|
||||||
('News', 'http://www.independent.ie/rss'),
|
('News', 'http://www.independent.ie/rss'),
|
||||||
|
('World News', 'http://www.independent.ie/world-news/rss'),
|
||||||
('Opinion', 'http://www.independent.ie/opinion/rss'),
|
('Opinion', 'http://www.independent.ie/opinion/rss'),
|
||||||
('Business', 'http://www.independent.ie/business/rss'),
|
('Business', 'http://www.independent.ie/business/rss'),
|
||||||
('Sport', 'http://www.independent.ie/sport/rss'),
|
('Sport', 'http://www.independent.ie/sport/rss'),
|
||||||
|
@ -2401,7 +2401,7 @@ class Cache:
|
|||||||
|
|
||||||
Example: Assume author A has link X, author B has link Y, tag S has link
|
Example: Assume author A has link X, author B has link Y, tag S has link
|
||||||
F, and tag T has link G. If book 1 has author A and tag T,
|
F, and tag T has link G. If book 1 has author A and tag T,
|
||||||
this method returns {'authors':{'A':'X'}, 'tags':{'T', 'G'}}
|
this method returns {'authors':{'A':'X'}, 'tags':{'T', 'G'}}.
|
||||||
If book 2's author is neither A nor B and has no tags, this method returns {}.
|
If book 2's author is neither A nor B and has no tags, this method returns {}.
|
||||||
|
|
||||||
:param book_id: the book id in question.
|
:param book_id: the book id in question.
|
||||||
|
@ -88,9 +88,10 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(_('&OK'))
|
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(_('&OK'))
|
||||||
self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(_('&Cancel'))
|
self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(_('&Cancel'))
|
||||||
self.buttonBox.accepted.connect(self.accepted)
|
self.buttonBox.accepted.connect(self.accepted)
|
||||||
|
self.buttonBox.rejected.connect(self.rejected)
|
||||||
self.apply_vl_checkbox.stateChanged.connect(self.use_vl_changed)
|
self.apply_vl_checkbox.stateChanged.connect(self.use_vl_changed)
|
||||||
|
|
||||||
# Set up the heading for sorting
|
self.table.setAlternatingRowColors(True)
|
||||||
self.table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
self.table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||||
|
|
||||||
self.find_aut_func = find_aut_func
|
self.find_aut_func = find_aut_func
|
||||||
@ -112,6 +113,10 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
hh.sectionClicked.connect(self.do_sort)
|
hh.sectionClicked.connect(self.do_sort)
|
||||||
hh.setSortIndicatorShown(True)
|
hh.setSortIndicatorShown(True)
|
||||||
|
|
||||||
|
vh = self.table.verticalHeader()
|
||||||
|
vh.setDefaultSectionSize(gprefs.get('general_category_editor_row_height', vh.defaultSectionSize()))
|
||||||
|
vh.sectionResized.connect(self.row_height_changed)
|
||||||
|
|
||||||
# set up the search & filter boxes
|
# set up the search & filter boxes
|
||||||
self.find_box.initialize('manage_authors_search')
|
self.find_box.initialize('manage_authors_search')
|
||||||
le = self.find_box.lineEdit()
|
le = self.find_box.lineEdit()
|
||||||
@ -271,10 +276,16 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
self.start_find_pos = -1
|
self.start_find_pos = -1
|
||||||
self.table.blockSignals(False)
|
self.table.blockSignals(False)
|
||||||
|
|
||||||
|
def row_height_changed(self, row, old, new):
|
||||||
|
self.table.verticalHeader().blockSignals(True)
|
||||||
|
self.table.verticalHeader().setDefaultSectionSize(new)
|
||||||
|
self.table.verticalHeader().blockSignals(False)
|
||||||
|
|
||||||
def save_state(self):
|
def save_state(self):
|
||||||
self.table_column_widths = []
|
self.table_column_widths = []
|
||||||
for c in range(0, self.table.columnCount()):
|
for c in range(0, self.table.columnCount()):
|
||||||
self.table_column_widths.append(self.table.columnWidth(c))
|
self.table_column_widths.append(self.table.columnWidth(c))
|
||||||
|
gprefs['general_category_editor_row_height'] = self.table.verticalHeader().sectionSize(0)
|
||||||
gprefs['manage_authors_table_widths'] = self.table_column_widths
|
gprefs['manage_authors_table_widths'] = self.table_column_widths
|
||||||
self.save_geometry(gprefs, 'manage_authors_dialog_geometry')
|
self.save_geometry(gprefs, 'manage_authors_dialog_geometry')
|
||||||
|
|
||||||
@ -451,6 +462,9 @@ class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
|||||||
if orig != v:
|
if orig != v:
|
||||||
self.result.append((id_, orig['name'], v['name'], v['sort'], v['link']))
|
self.result.append((id_, orig['name'], v['name'], v['sort'], v['link']))
|
||||||
|
|
||||||
|
def rejected(self):
|
||||||
|
self.save_state()
|
||||||
|
|
||||||
def do_recalc_author_sort(self):
|
def do_recalc_author_sort(self):
|
||||||
with self.no_cell_changed():
|
with self.no_cell_changed():
|
||||||
for row in range(0,self.table.rowCount()):
|
for row in range(0,self.table.rowCount()):
|
||||||
|
@ -165,12 +165,6 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.setWindowFlags(self.windowFlags()&(~Qt.WindowType.WindowContextHelpButtonHint))
|
self.setWindowFlags(self.windowFlags()&(~Qt.WindowType.WindowContextHelpButtonHint))
|
||||||
self.setWindowIcon(icon)
|
self.setWindowIcon(icon)
|
||||||
|
|
||||||
# Get saved geometry info
|
|
||||||
try:
|
|
||||||
self.table_column_widths = gprefs.get('tag_list_editor_table_widths', None)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# initialization
|
# initialization
|
||||||
self.to_rename = {}
|
self.to_rename = {}
|
||||||
self.to_delete = set()
|
self.to_delete = set()
|
||||||
@ -370,6 +364,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
# I'm not sure if this is standard Qt behavior or behavior triggered by
|
# I'm not sure if this is standard Qt behavior or behavior triggered by
|
||||||
# something in this class, but replacing the table fixes it.
|
# something in this class, but replacing the table fixes it.
|
||||||
if self.table is not None:
|
if self.table is not None:
|
||||||
|
self.save_geometry()
|
||||||
self.gridlayout.removeWidget(self.table)
|
self.gridlayout.removeWidget(self.table)
|
||||||
sip.delete(self.table)
|
sip.delete(self.table)
|
||||||
self.table = TleTableWidget(self)
|
self.table = TleTableWidget(self)
|
||||||
@ -386,9 +381,11 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
hh.sectionClicked.connect(self.record_sort)
|
hh.sectionClicked.connect(self.record_sort)
|
||||||
hh.setSortIndicatorShown(True)
|
hh.setSortIndicatorShown(True)
|
||||||
|
|
||||||
|
vh = self.table.verticalHeader()
|
||||||
|
vh.setDefaultSectionSize(gprefs.get('general_category_editor_row_height', vh.defaultSectionSize()))
|
||||||
|
vh.sectionResized.connect(self.row_height_changed)
|
||||||
|
|
||||||
self.table.setColumnCount(4)
|
self.table.setColumnCount(4)
|
||||||
for col,width in enumerate(self.table_column_widths):
|
|
||||||
self.table.setColumnWidth(col, width)
|
|
||||||
|
|
||||||
self.edit_delegate = EditColumnDelegate(self.table, self.check_for_deleted_items)
|
self.edit_delegate = EditColumnDelegate(self.table, self.check_for_deleted_items)
|
||||||
self.edit_delegate.editing_finished.connect(self.stop_editing)
|
self.edit_delegate.editing_finished.connect(self.stop_editing)
|
||||||
@ -416,11 +413,21 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.not_found_label_timer_event, type=Qt.ConnectionType.QueuedConnection)
|
self.not_found_label_timer_event, type=Qt.ConnectionType.QueuedConnection)
|
||||||
|
|
||||||
self.table.setEditTriggers(QAbstractItemView.EditTrigger.EditKeyPressed)
|
self.table.setEditTriggers(QAbstractItemView.EditTrigger.EditKeyPressed)
|
||||||
|
|
||||||
self.restore_geometry(gprefs, 'tag_list_editor_dialog_geometry')
|
self.restore_geometry(gprefs, 'tag_list_editor_dialog_geometry')
|
||||||
|
self.table_column_widths = gprefs.get('tag_list_editor_table_widths', None)
|
||||||
|
if self.table_column_widths is not None:
|
||||||
|
for col,width in enumerate(self.table_column_widths):
|
||||||
|
self.table.setColumnWidth(col, width)
|
||||||
|
|
||||||
self.table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
self.table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||||
self.table.customContextMenuRequested.connect(self.show_context_menu)
|
self.table.customContextMenuRequested.connect(self.show_context_menu)
|
||||||
|
|
||||||
|
def row_height_changed(self, row, old, new):
|
||||||
|
self.table.verticalHeader().blockSignals(True)
|
||||||
|
self.table.verticalHeader().setDefaultSectionSize(new)
|
||||||
|
self.table.verticalHeader().blockSignals(False)
|
||||||
|
|
||||||
def fill_in_table(self, tags, tag_to_match, ttm_is_first_letter):
|
def fill_in_table(self, tags, tag_to_match, ttm_is_first_letter):
|
||||||
self.create_table()
|
self.create_table()
|
||||||
|
|
||||||
@ -532,7 +539,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
def do_filter(self):
|
def do_filter(self):
|
||||||
self.fill_in_table(None, None, False)
|
self.fill_in_table(None, None, False)
|
||||||
|
|
||||||
def table_column_resized(self, col, old, new):
|
def table_column_resized(self, *args):
|
||||||
self.table_column_widths = []
|
self.table_column_widths = []
|
||||||
for c in range(0, self.table.columnCount()):
|
for c in range(0, self.table.columnCount()):
|
||||||
self.table_column_widths.append(self.table.columnWidth(c))
|
self.table_column_widths.append(self.table.columnWidth(c))
|
||||||
@ -552,6 +559,7 @@ class TagListEditor(QDialog, Ui_TagListEditor):
|
|||||||
self.table.setColumnWidth(c, w)
|
self.table.setColumnWidth(c, w)
|
||||||
|
|
||||||
def save_geometry(self):
|
def save_geometry(self):
|
||||||
|
gprefs['general_category_editor_row_height'] = self.table.verticalHeader().sectionSize(0)
|
||||||
gprefs['tag_list_editor_table_widths'] = self.table_column_widths
|
gprefs['tag_list_editor_table_widths'] = self.table_column_widths
|
||||||
super().save_geometry(gprefs, 'tag_list_editor_dialog_geometry')
|
super().save_geometry(gprefs, 'tag_list_editor_dialog_geometry')
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ if __name__ == '__main__':
|
|||||||
w.setWindowFlag(Qt.WindowType.Dialog)
|
w.setWindowFlag(Qt.WindowType.Dialog)
|
||||||
w.show()
|
w.show()
|
||||||
w.markdown = '''\
|
w.markdown = '''\
|
||||||
test *italic* **bold** ***bold-italic*** `code` [link](https://calibre-ebook.com) <span style="font-weight: bold; color:red">span</span>
|
normal& *italic&* **bold&** ***bold-italic*** `code` [link](https://calibre-ebook.com) <span style="font-weight: bold; color:red">span</span>
|
||||||
|
|
||||||
> Blockquotes
|
> Blockquotes
|
||||||
|
|
||||||
|
@ -20,19 +20,20 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
|||||||
'uBold': re.compile(r'(?<!\\)(?P<delim>__)(?P<text>.+?)(?P=delim)'),
|
'uBold': re.compile(r'(?<!\\)(?P<delim>__)(?P<text>.+?)(?P=delim)'),
|
||||||
'uItalic': re.compile(r'(?<![_\\])(?P<delim>_)(?!_)(?P<text>([^_]{2,}?|[^_]))(?<![_\\])(?P=delim)'),
|
'uItalic': re.compile(r'(?<![_\\])(?P<delim>_)(?!_)(?P<text>([^_]{2,}?|[^_]))(?<![_\\])(?P=delim)'),
|
||||||
'uBoldItalic': re.compile(r'(?<!\\)(?P<delim>___)(?P<text>([^_]{2,}?|[^_]))(?<!\\)(?P=delim)'),
|
'uBoldItalic': re.compile(r'(?<!\\)(?P<delim>___)(?P<text>([^_]{2,}?|[^_]))(?<!\\)(?P=delim)'),
|
||||||
'Link': re.compile(r'(?u)(?<![!\\]])\[.*?(?<!\\)\](\[.+?(?<!\\)\]|\(.+?(?<!\\)\))'),
|
'Link': re.compile(r'(?<![!\\]])\[.*?(?<!\\)\](\[.+?(?<!\\)\]|\(.+?(?<!\\)\))'),
|
||||||
'Image': re.compile(r'(?u)(?<!\\)!\[.*?(?<!\\)\](\[.+?(?<!\\)\]|\(.+?(?<!\\)\))'),
|
'Image': re.compile(r'(?<!\\)!\[.*?(?<!\\)\](\[.+?(?<!\\)\]|\(.+?(?<!\\)\))'),
|
||||||
'LinkRef': re.compile(r'(?u)^ *\[.*?\]:[ \t]*.*$'),
|
'LinkRef': re.compile(r'(?u)^\s*\[.*?\]:\s*[^\s].*'),
|
||||||
'Header': re.compile(r'(?u)^#{1,6}(.*?)$'),
|
'Header': re.compile(r'^#{1,6}.*'),
|
||||||
'CodeBlock': re.compile('^([ ]{4,}|\t).*'),
|
'UnorderedList': re.compile(r'(?u)^\s*(\*|\+|-)[ \t]\s*'),
|
||||||
'UnorderedList': re.compile(r'(?u)^\s*(\* |\+ |- )+\s*'),
|
'UnorderedListStar': re.compile(r'(?u)^\s*\*[ \t]\s*'),
|
||||||
'UnorderedListStar': re.compile(r'^\s*(\* )+\s*'),
|
'OrderedList': re.compile(r'(?u)^\s*\d+\.[ \t]\s*'),
|
||||||
'OrderedList': re.compile(r'(?u)^\s*(\d+\. )\s*'),
|
'BlockQuote': re.compile(r'^[ ]{0,3}>+[ \t]?'),
|
||||||
'BlockQuote': re.compile(r'(?u)^[ ]{0,3}>+[ \t]?'),
|
'CodeBlock': re.compile(r'^([ ]{4,}|[ ]*\t).*'),
|
||||||
'CodeSpan': re.compile(r'(?<!\\)(?P<delim>`+).+?(?P=delim)'),
|
'CodeSpan': re.compile(r'(?<!\\)(?P<delim>`+).+?(?P=delim)'),
|
||||||
'HeaderLine': re.compile(r'(?u)^(-|=)+\s*$'),
|
'HeaderLine': re.compile(r'(?u)^(-|=)+\s*$'),
|
||||||
'HR': re.compile(r'(?u)^(\s*(\*|-|_)\s*){3,}$'),
|
'HR': re.compile(r'(?u)^(\s*(\*|-|_)\s*){3,}$'),
|
||||||
'Html': re.compile(r'<.+?(?<!\\)>')
|
'Html': re.compile(r'(?u)</?[^/\s].*?(?<!\\)>'),
|
||||||
|
'Entity': re.compile(r'&([A-z]{2,7}|#\d{1,7}|#x[\dA-Fa-f]{1,6});'),
|
||||||
}
|
}
|
||||||
|
|
||||||
key_theme_maps = {
|
key_theme_maps = {
|
||||||
@ -55,6 +56,7 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
|||||||
'CodeSpan': "codespan",
|
'CodeSpan': "codespan",
|
||||||
'HR': "line",
|
'HR': "line",
|
||||||
'Html': "html",
|
'Html': "html",
|
||||||
|
'Entity': "entity",
|
||||||
}
|
}
|
||||||
|
|
||||||
light_theme = {
|
light_theme = {
|
||||||
@ -70,7 +72,8 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
|||||||
"codespan": {"color":"#ff5800", "font-weight":"normal", "font-style":"normal"},
|
"codespan": {"color":"#ff5800", "font-weight":"normal", "font-style":"normal"},
|
||||||
"codeblock": {"color":"#ff5800", "font-weight":"normal", "font-style":"normal"},
|
"codeblock": {"color":"#ff5800", "font-weight":"normal", "font-style":"normal"},
|
||||||
"line": {"color":"#2aa198", "font-weight":"normal", "font-style":"normal"},
|
"line": {"color":"#2aa198", "font-weight":"normal", "font-style":"normal"},
|
||||||
"html": {"color":"#c000c0", "font-weight":"normal", "font-style":"normal"}
|
"html": {"color":"#c000c0", "font-weight":"normal", "font-style":"normal"},
|
||||||
|
"entity": {"color":"#006496"},
|
||||||
}
|
}
|
||||||
|
|
||||||
dark_theme = {
|
dark_theme = {
|
||||||
@ -86,7 +89,8 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
|||||||
"codespan": {"color":"#90ee90", "font-weight":"normal", "font-style":"normal"},
|
"codespan": {"color":"#90ee90", "font-weight":"normal", "font-style":"normal"},
|
||||||
"codeblock": {"color":"#ff9900", "font-weight":"normal", "font-style":"normal"},
|
"codeblock": {"color":"#ff9900", "font-weight":"normal", "font-style":"normal"},
|
||||||
"line": {"color":"#2aa198", "font-weight":"normal", "font-style":"normal"},
|
"line": {"color":"#2aa198", "font-weight":"normal", "font-style":"normal"},
|
||||||
"html": {"color":"#F653A6", "font-weight":"normal", "font-style":"normal"}
|
"html": {"color":"#f653a6", "font-weight":"normal", "font-style":"normal"},
|
||||||
|
"entity": {"color":"#ff82ac"},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
@ -98,6 +102,16 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
|||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.MARKDOWN_KWS_FORMAT = {}
|
self.MARKDOWN_KWS_FORMAT = {}
|
||||||
|
|
||||||
|
for k in ['Bold', 'Italic','BoldItalic']:
|
||||||
|
# generate dynamically keys and theme for EntityBold, EntityItalic, EntityBoldItalic
|
||||||
|
t = self.key_theme_maps[k]
|
||||||
|
newtheme = theme['entity'].copy()
|
||||||
|
newtheme.update(theme[t])
|
||||||
|
newthemekey = 'entity'+t
|
||||||
|
newmapkey = 'Entity'+k
|
||||||
|
theme[newthemekey] = newtheme
|
||||||
|
self.key_theme_maps[newmapkey] = newthemekey
|
||||||
|
|
||||||
for k,t in self.key_theme_maps.items():
|
for k,t in self.key_theme_maps.items():
|
||||||
subtheme = theme[t]
|
subtheme = theme[t]
|
||||||
format = QTextCharFormat()
|
format = QTextCharFormat()
|
||||||
@ -141,13 +155,15 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
|||||||
|
|
||||||
self.highlightImage(text, cursor, bf)
|
self.highlightImage(text, cursor, bf)
|
||||||
|
|
||||||
|
self.highlightEntity(text, cursor, bf)
|
||||||
|
|
||||||
self.highlightCodeSpan(text, cursor, bf)
|
self.highlightCodeSpan(text, cursor, bf)
|
||||||
|
|
||||||
self.highlightCodeBlock(text, cursor, bf)
|
self.highlightCodeBlock(text, cursor, bf)
|
||||||
|
|
||||||
def highlightBlockQuote(self, text, cursor, bf):
|
def highlightBlockQuote(self, text, cursor, bf):
|
||||||
found = False
|
found = False
|
||||||
mo = re.search(self.MARKDOWN_KEYS_REGEX['BlockQuote'],text)
|
mo = re.match(self.MARKDOWN_KEYS_REGEX['BlockQuote'],text)
|
||||||
if mo:
|
if mo:
|
||||||
self.setFormat(self.offset+ mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['BlockQuote'])
|
self.setFormat(self.offset+ mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['BlockQuote'])
|
||||||
self.offset += mo.end()
|
self.offset += mo.end()
|
||||||
@ -290,11 +306,29 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
|||||||
found = False
|
found = False
|
||||||
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['CodeBlock'],text):
|
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['CodeBlock'],text):
|
||||||
stripped = text.lstrip()
|
stripped = text.lstrip()
|
||||||
if stripped[0] not in ('*','-','+','>') and not re.match(r'\d+\.', stripped):
|
if stripped[0] not in ('*','-','+') and not re.match(self.MARKDOWN_KEYS_REGEX['OrderedList'], stripped):
|
||||||
self.setFormat(self.offset+ mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['CodeBlock'])
|
self.setFormat(self.offset+ mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['CodeBlock'])
|
||||||
found = True
|
found = True
|
||||||
return found
|
return found
|
||||||
|
|
||||||
|
def highlightEntity(self, text, cursor, bf):
|
||||||
|
found = False
|
||||||
|
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['Entity'],text):
|
||||||
|
charformat = self.format(self.offset+ mo.start())
|
||||||
|
charbold = charformat.fontWeight() == QFont.Weight.Bold
|
||||||
|
charitalic = charformat.fontItalic()
|
||||||
|
if charbold and charitalic:
|
||||||
|
format = self.MARKDOWN_KWS_FORMAT['EntityBoldItalic']
|
||||||
|
elif charbold and not charitalic:
|
||||||
|
format = self.MARKDOWN_KWS_FORMAT['EntityBold']
|
||||||
|
elif not charbold and charitalic:
|
||||||
|
format = self.MARKDOWN_KWS_FORMAT['EntityItalic']
|
||||||
|
else:
|
||||||
|
format = self.MARKDOWN_KWS_FORMAT['Entity']
|
||||||
|
self.setFormat(self.offset+ mo.start(), mo.end() - mo.start(), format)
|
||||||
|
found = True
|
||||||
|
return found
|
||||||
|
|
||||||
def highlightHtml(self, text):
|
def highlightHtml(self, text):
|
||||||
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['Html'], text):
|
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['Html'], text):
|
||||||
self.setFormat(mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['Html'])
|
self.setFormat(mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['Html'])
|
||||||
|
@ -1070,7 +1070,7 @@ class TOCEditor(QDialog): # {{{
|
|||||||
def workaround_macos_mouse_with_webview_bug(self):
|
def workaround_macos_mouse_with_webview_bug(self):
|
||||||
# macOS is weird: https://bugs.launchpad.net/calibre/+bug/2004639
|
# macOS is weird: https://bugs.launchpad.net/calibre/+bug/2004639
|
||||||
# needed as of Qt 6.4.2
|
# needed as of Qt 6.4.2
|
||||||
d = info_dialog(self, _('Loading...'), _('Loading view, please wait...'), show_copy_button=False)
|
d = info_dialog(self, _('Loading...'), _('Loading table of contents view, please wait...'), show_copy_button=False)
|
||||||
QTimer.singleShot(0, d.reject)
|
QTimer.singleShot(0, d.reject)
|
||||||
d.exec()
|
d.exec()
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ class TrashView(Dialog):
|
|||||||
return
|
return
|
||||||
det_msg = []
|
det_msg = []
|
||||||
for (entry, exc, tb) in failures:
|
for (entry, exc, tb) in failures:
|
||||||
det_msg.append(_('Failed for {} with error:').format(entry.title))
|
det_msg.append(_('Failed for the book {} with error:').format(entry.title))
|
||||||
det_msg.append(tb)
|
det_msg.append(tb)
|
||||||
det_msg.append('-' * 40)
|
det_msg.append('-' * 40)
|
||||||
det_msg.append('')
|
det_msg.append('')
|
||||||
|
@ -68,7 +68,7 @@ class TOCEditor(QDialog):
|
|||||||
def workaround_macos_mouse_with_webview_bug(self):
|
def workaround_macos_mouse_with_webview_bug(self):
|
||||||
# macOS is weird: https://bugs.launchpad.net/calibre/+bug/2004639
|
# macOS is weird: https://bugs.launchpad.net/calibre/+bug/2004639
|
||||||
# needed as of Qt 6.4.2
|
# needed as of Qt 6.4.2
|
||||||
d = info_dialog(self, _('Loading...'), _('Loading view, please wait...'), show_copy_button=False)
|
d = info_dialog(self, _('Loading...'), _('Loading table of contents view, please wait...'), show_copy_button=False)
|
||||||
QTimer.singleShot(0, d.reject)
|
QTimer.singleShot(0, d.reject)
|
||||||
d.exec()
|
d.exec()
|
||||||
|
|
||||||
|
@ -177,72 +177,75 @@ class CSV_XML(CatalogPlugin):
|
|||||||
else:
|
else:
|
||||||
root = E.calibredb()
|
root = E.calibredb()
|
||||||
for r in data:
|
for r in data:
|
||||||
record = E.record()
|
try:
|
||||||
root.append(record)
|
record = E.record()
|
||||||
|
root.append(record)
|
||||||
|
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if field.startswith('#'):
|
if field.startswith('#'):
|
||||||
val = db.get_field(r['id'], field, index_is_id=True)
|
val = db.get_field(r['id'], field, index_is_id=True)
|
||||||
if not isinstance(val, str):
|
if not isinstance(val, str):
|
||||||
val = str(val)
|
val = str(val)
|
||||||
item = getattr(E, field.replace('#', '_'))(val)
|
item = getattr(E, field.replace('#', '_'))(val)
|
||||||
record.append(item)
|
record.append(item)
|
||||||
|
|
||||||
for field in ('id', 'uuid', 'publisher', 'rating', 'size',
|
for field in ('id', 'uuid', 'publisher', 'rating', 'size',
|
||||||
'isbn', 'ondevice', 'identifiers'):
|
'isbn', 'ondevice', 'identifiers'):
|
||||||
if field in fields:
|
if field in fields:
|
||||||
val = r[field]
|
val = r[field]
|
||||||
if not val:
|
if not val:
|
||||||
continue
|
continue
|
||||||
if not isinstance(val, (bytes, str)):
|
if not isinstance(val, (bytes, str)):
|
||||||
if (fm.get(field, {}).get('datatype', None) ==
|
if (fm.get(field, {}).get('datatype', None) ==
|
||||||
'rating' and val):
|
'rating' and val):
|
||||||
val = '%.2g' % (val / 2)
|
val = '%.2g' % (val / 2)
|
||||||
val = str(val)
|
val = str(val)
|
||||||
item = getattr(E, field)(val)
|
item = getattr(E, field)(val)
|
||||||
record.append(item)
|
record.append(item)
|
||||||
|
|
||||||
if 'title' in fields:
|
if 'title' in fields:
|
||||||
title = E.title(r['title'], sort=r['sort'])
|
title = E.title(r['title'], sort=r['sort'])
|
||||||
record.append(title)
|
record.append(title)
|
||||||
|
|
||||||
if 'authors' in fields:
|
if 'authors' in fields:
|
||||||
aus = E.authors(sort=r['author_sort'])
|
aus = E.authors(sort=r['author_sort'])
|
||||||
for au in r['authors']:
|
for au in r['authors']:
|
||||||
aus.append(E.author(au))
|
aus.append(E.author(au))
|
||||||
record.append(aus)
|
record.append(aus)
|
||||||
|
|
||||||
for field in ('timestamp', 'pubdate'):
|
for field in ('timestamp', 'pubdate'):
|
||||||
if field in fields:
|
if field in fields:
|
||||||
record.append(getattr(E, field)(isoformat(r[field], as_utc=False)))
|
record.append(getattr(E, field)(isoformat(r[field], as_utc=False)))
|
||||||
|
|
||||||
if 'tags' in fields and r['tags']:
|
if 'tags' in fields and r['tags']:
|
||||||
tags = E.tags()
|
tags = E.tags()
|
||||||
for tag in r['tags']:
|
for tag in r['tags']:
|
||||||
tags.append(E.tag(tag))
|
tags.append(E.tag(tag))
|
||||||
record.append(tags)
|
record.append(tags)
|
||||||
|
|
||||||
if 'comments' in fields and r['comments']:
|
if 'comments' in fields and r['comments']:
|
||||||
record.append(E.comments(r['comments']))
|
record.append(E.comments(r['comments']))
|
||||||
|
|
||||||
if 'series' in fields and r['series']:
|
if 'series' in fields and r['series']:
|
||||||
record.append(E.series(r['series'],
|
record.append(E.series(r['series'],
|
||||||
index=str(r['series_index'])))
|
index=str(r['series_index'])))
|
||||||
|
|
||||||
if 'languages' in fields and r['languages']:
|
if 'languages' in fields and r['languages']:
|
||||||
record.append(E.languages(r['languages']))
|
record.append(E.languages(r['languages']))
|
||||||
|
|
||||||
if 'cover' in fields and r['cover']:
|
if 'cover' in fields and r['cover']:
|
||||||
record.append(E.cover(r['cover'].replace(os.sep, '/')))
|
record.append(E.cover(r['cover'].replace(os.sep, '/')))
|
||||||
|
|
||||||
if 'formats' in fields and r['formats']:
|
if 'formats' in fields and r['formats']:
|
||||||
fmt = E.formats()
|
fmt = E.formats()
|
||||||
for f in r['formats']:
|
for f in r['formats']:
|
||||||
fmt.append(E.format(f.replace(os.sep, '/')))
|
fmt.append(E.format(f.replace(os.sep, '/')))
|
||||||
record.append(fmt)
|
record.append(fmt)
|
||||||
|
|
||||||
if 'library_name' in fields:
|
if 'library_name' in fields:
|
||||||
record.append(E.library_name(current_library))
|
record.append(E.library_name(current_library))
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception('Failed to convert {} to XML with error: {}'.format(r['title'], e)) from e
|
||||||
|
|
||||||
with open(path_to_output, 'wb') as f:
|
with open(path_to_output, 'wb') as f:
|
||||||
f.write(etree.tostring(root, encoding='utf-8',
|
f.write(etree.tostring(root, encoding='utf-8',
|
||||||
|
@ -53,7 +53,7 @@ class TestResult(unittest.TextTestResult):
|
|||||||
|
|
||||||
|
|
||||||
def find_tests_in_package(package, excludes=('main.py',)):
|
def find_tests_in_package(package, excludes=('main.py',)):
|
||||||
items = list(importlib.resources.contents(package))
|
items = [path.name for path in importlib.resources.files(package).iterdir()]
|
||||||
suits = []
|
suits = []
|
||||||
excludes = set(excludes) | {x + 'c' for x in excludes}
|
excludes = set(excludes) | {x + 'c' for x in excludes}
|
||||||
seen = set()
|
seen = set()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user