mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Button to export highlights from viewer
This commit is contained in:
parent
0bdde24493
commit
7bac3a8737
@ -14,6 +14,7 @@ vprefs.defaults['main_window_state'] = None
|
|||||||
vprefs.defaults['main_window_geometry'] = None
|
vprefs.defaults['main_window_geometry'] = None
|
||||||
vprefs.defaults['old_prefs_migrated'] = False
|
vprefs.defaults['old_prefs_migrated'] = False
|
||||||
vprefs.defaults['bookmarks_sort'] = 'title'
|
vprefs.defaults['bookmarks_sort'] = 'title'
|
||||||
|
vprefs.defaults['highlight_export_format'] = 'txt'
|
||||||
|
|
||||||
|
|
||||||
def get_session_pref(name, default=None, group='standalone_misc_settings'):
|
def get_session_pref(name, default=None, group='standalone_misc_settings'):
|
||||||
|
@ -2,24 +2,95 @@
|
|||||||
# vim:fileencoding=utf-8
|
# vim:fileencoding=utf-8
|
||||||
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
import json
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QHBoxLayout, QIcon, QItemSelectionModel, QKeySequence, QLabel, QListWidget,
|
QApplication, QComboBox, QDateTime, QFormLayout, QHBoxLayout, QIcon,
|
||||||
QListWidgetItem, QPushButton, Qt, QTextEdit, QToolButton, QVBoxLayout, QWidget,
|
QItemSelectionModel, QKeySequence, QLabel, QListWidget, QListWidgetItem,
|
||||||
pyqtSignal
|
QPushButton, Qt, QTextEdit, QToolButton, QVBoxLayout, QWidget, pyqtSignal
|
||||||
)
|
)
|
||||||
|
|
||||||
from calibre.constants import plugins
|
from calibre.constants import plugins
|
||||||
from calibre.ebooks.epub.cfi.parse import cfi_sort_key
|
from calibre.ebooks.epub.cfi.parse import cfi_sort_key
|
||||||
from calibre.gui2 import error_dialog, question_dialog
|
from calibre.gui2 import choose_save_file, error_dialog, question_dialog
|
||||||
from calibre.gui2.library.annotations import Details
|
from calibre.gui2.library.annotations import Details
|
||||||
|
from calibre.gui2.viewer.config import vprefs
|
||||||
from calibre.gui2.viewer.search import SearchInput
|
from calibre.gui2.viewer.search import SearchInput
|
||||||
from calibre.gui2.viewer.shortcuts import index_to_key_sequence
|
from calibre.gui2.viewer.shortcuts import index_to_key_sequence
|
||||||
from calibre.gui2.widgets2 import Dialog
|
from calibre.gui2.widgets2 import Dialog
|
||||||
from polyglot.builtins import range
|
from polyglot.builtins import range
|
||||||
|
|
||||||
|
|
||||||
|
class Export(Dialog):
|
||||||
|
|
||||||
|
def __init__(self, highlights, parent=None):
|
||||||
|
self.highlights = highlights
|
||||||
|
super().__init__('export-highlights', _('Export {} highlights').format(len(highlights)), parent=parent)
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
self.l = l = QFormLayout(self)
|
||||||
|
self.export_format = ef = QComboBox(self)
|
||||||
|
ef.addItem(_('Plain text'), 'txt')
|
||||||
|
ef.addItem(_('calibre highlights'), 'calibre_highlights')
|
||||||
|
idx = ef.findData(vprefs['highlight_export_format'])
|
||||||
|
if idx > -1:
|
||||||
|
ef.setCurrentIndex(idx)
|
||||||
|
ef.currentIndexChanged.connect(self.save_format_pref)
|
||||||
|
l.addRow(_('Format to export in:'), ef)
|
||||||
|
l.addRow(self.bb)
|
||||||
|
self.bb.clear()
|
||||||
|
self.bb.addButton(self.bb.Cancel)
|
||||||
|
b = self.bb.addButton(_('Copy to clipboard'), self.bb.ActionRole)
|
||||||
|
b.clicked.connect(self.copy_to_clipboard)
|
||||||
|
b.setIcon(QIcon(I('edit-copy.png')))
|
||||||
|
b = self.bb.addButton(_('Save to file'), self.bb.ActionRole)
|
||||||
|
b.clicked.connect(self.save_to_file)
|
||||||
|
b.setIcon(QIcon(I('save.png')))
|
||||||
|
|
||||||
|
def save_format_pref(self):
|
||||||
|
vprefs['highlight_export_format'] = self.export_format.currentData()
|
||||||
|
|
||||||
|
def copy_to_clipboard(self):
|
||||||
|
QApplication.instance().clipboard().setText(self.exported_data)
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
def save_to_file(self):
|
||||||
|
filters = [(self.export_format.currentText(), self.export_format.currentData())]
|
||||||
|
path = choose_save_file(
|
||||||
|
self, 'highlights-export-save', _('File for exports'), filters=filters,
|
||||||
|
initial_filename=_('highlights') + '.' + filters[0][1])
|
||||||
|
if path:
|
||||||
|
data = self.exported_data.encode('utf-8')
|
||||||
|
with open(path, 'wb') as f:
|
||||||
|
f.write(codecs.BOM_UTF8)
|
||||||
|
f.write(data)
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def exported_data(self):
|
||||||
|
if self.export_format.currentData() == 'calibre_highlights':
|
||||||
|
return json.dumps({
|
||||||
|
'version': 1,
|
||||||
|
'type': 'calibre_highlights',
|
||||||
|
'highlights': self.highlights
|
||||||
|
}, ensure_ascii=False, sort_keys=True, indent=2)
|
||||||
|
lines = []
|
||||||
|
for hl in self.highlights:
|
||||||
|
lines.append(hl['highlighted_text'])
|
||||||
|
date = QDateTime.fromString(hl['timestamp'], Qt.ISODate).toLocalTime().toString(Qt.SystemLocaleShortDate)
|
||||||
|
lines.append(date)
|
||||||
|
notes = hl.get('notes')
|
||||||
|
if notes:
|
||||||
|
lines.append('')
|
||||||
|
lines.append(notes)
|
||||||
|
lines.append('')
|
||||||
|
lines.append('───')
|
||||||
|
lines.append('')
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
class Highlights(QListWidget):
|
class Highlights(QListWidget):
|
||||||
|
|
||||||
jump_to_highlight = pyqtSignal(object)
|
jump_to_highlight = pyqtSignal(object)
|
||||||
@ -97,6 +168,12 @@ class Highlights(QListWidget):
|
|||||||
if i is not None:
|
if i is not None:
|
||||||
return i.data(Qt.UserRole)
|
return i.data(Qt.UserRole)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def all_highlights(self):
|
||||||
|
for i in range(self.count()):
|
||||||
|
item = self.item(i)
|
||||||
|
yield item.data(Qt.UserRole)
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
def keyPressEvent(self, ev):
|
||||||
if ev.matches(QKeySequence.Delete):
|
if ev.matches(QKeySequence.Delete):
|
||||||
self.delete_requested.emit()
|
self.delete_requested.emit()
|
||||||
@ -204,6 +281,9 @@ class HighlightsPanel(QWidget):
|
|||||||
self.remove_button = button('trash.png', _('Remove'), _('Remove the selected highlight'), self.remove_highlight)
|
self.remove_button = button('trash.png', _('Remove'), _('Remove the selected highlight'), self.remove_highlight)
|
||||||
h.addWidget(self.add_button), h.addWidget(self.edit_button), h.addWidget(self.remove_button)
|
h.addWidget(self.add_button), h.addWidget(self.edit_button), h.addWidget(self.remove_button)
|
||||||
|
|
||||||
|
self.export_button = button('save.png', _('Export'), _('Export all highlights'), self.export)
|
||||||
|
l.addWidget(self.export_button)
|
||||||
|
|
||||||
self.notes_display = nd = NotesDisplay(self)
|
self.notes_display = nd = NotesDisplay(self)
|
||||||
nd.notes_edited.connect(self.notes_edited)
|
nd.notes_edited.connect(self.notes_edited)
|
||||||
l.addWidget(nd)
|
l.addWidget(nd)
|
||||||
@ -266,3 +346,9 @@ class HighlightsPanel(QWidget):
|
|||||||
|
|
||||||
def add_highlight(self):
|
def add_highlight(self):
|
||||||
self.request_highlight_action.emit(None, 'create')
|
self.request_highlight_action.emit(None, 'create')
|
||||||
|
|
||||||
|
def export(self):
|
||||||
|
hl = list(self.highlights.all_highlights)
|
||||||
|
if not hl:
|
||||||
|
return error_dialog(_('No highlights'), _('This book has no highlights to export'), show=True)
|
||||||
|
Export(hl, self).exec_()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user