From c8acbec3d1c19685001247f26f790fae7843a373 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 17 Sep 2023 16:08:06 +0530 Subject: [PATCH] Finish implementation of import/export of notes in note edit dialog --- src/calibre/db/notes/exim.py | 2 +- .../gui2/dialogs/edit_category_notes.py | 52 ++++++++++++++++--- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/calibre/db/notes/exim.py b/src/calibre/db/notes/exim.py index fb149f9a4e..b7a95a62aa 100644 --- a/src/calibre/db/notes/exim.py +++ b/src/calibre/db/notes/exim.py @@ -41,7 +41,7 @@ def export_note(note_doc: str, get_resource) -> str: return html.tostring(root, encoding='unicode') -def import_note(shtml: str | bytes, basedir: str, add_resource) -> dict: +def import_note(shtml: str | bytes, basedir: str, add_resource) -> tuple[str, str, set[str]]: shtml = xml_to_unicode(shtml, strip_encoding_pats=True, assume_utf8=True)[0] basedir = os.path.normcase(get_long_path_name(os.path.abspath(basedir)) + os.sep) root = parse_html(shtml) diff --git a/src/calibre/gui2/dialogs/edit_category_notes.py b/src/calibre/gui2/dialogs/edit_category_notes.py index ffcdcb79d9..1b2d9a8c26 100644 --- a/src/calibre/gui2/dialogs/edit_category_notes.py +++ b/src/calibre/gui2/dialogs/edit_category_notes.py @@ -3,16 +3,17 @@ import os from qt.core import ( - QButtonGroup, QByteArray, QDialog, QFormLayout, QHBoxLayout, QIcon, QLabel, - QLineEdit, QPixmap, QPushButton, QRadioButton, QSize, Qt, QTextDocument, - QTextFrameFormat, QTextImageFormat, QUrl, QVBoxLayout, QWidget, pyqtSlot, + QButtonGroup, QByteArray, QDialog, QDialogButtonBox, QFormLayout, QHBoxLayout, + QIcon, QLabel, QLineEdit, QPixmap, QPushButton, QRadioButton, QSize, Qt, + QTextDocument, QTextFrameFormat, QTextImageFormat, QUrl, QVBoxLayout, QWidget, + pyqtSlot, ) from typing import NamedTuple -from calibre.db.notes.connect import hash_data from calibre.db.constants import RESOURCE_URL_SCHEME -from calibre.db.notes.exim import export_note -from calibre.gui2 import Application, choose_images, error_dialog +from calibre.db.notes.connect import hash_data +from calibre.db.notes.exim import export_note, import_note +from calibre.gui2 import Application, choose_images, error_dialog, choose_save_file, choose_files from calibre.gui2.comments_editor import OBJECT_REPLACEMENT_CHAR, Editor, EditorWidget from calibre.gui2.widgets import ImageView from calibre.gui2.widgets2 import Dialog @@ -185,6 +186,17 @@ class NoteEditorWidget(EditorWidget): return {'name': ir.name, 'data': f.read()} return self.db.get_notes_resource(digest) + def add_resource(self, path_or_data, name): + if isinstance(path_or_data, str): + with open(path_or_data, 'rb') as f: + data = f.read() + else: + data = path_or_data + digest = hash_data(data) + ir = ImageResource(name, digest, data=data) + self.images[digest] = ir + return digest + @pyqtSlot(int, 'QUrl', result='QVariant') def loadResource(self, rtype, qurl): if self.db is None or self.images is None or qurl.scheme() != RESOURCE_URL_SCHEME or int(rtype) != int(QTextDocument.ResourceType.ImageResource): @@ -234,10 +246,17 @@ class NoteEditor(Editor): html = self.editor.html return html, self.editor.searchable_text, self.editor.referenced_resources, self.editor.images.values() - def export(self): - html, _, _ = self.get_doc() + def export_note(self): + html = self.get_doc()[0] return export_note(html, self.editor.get_resource) + def import_note(self, path_to_html_file): + self.editor.images = {} + self.editor.setPlainText('') + with open(path_to_html_file, 'rb') as f: + html, _, _ = import_note(f.read(), os.path.dirname(os.path.abspath(path_to_html_file)), self.editor.add_resource) + self.editor.html = html + class EditNoteWidget(QWidget): @@ -276,8 +295,25 @@ class EditNoteDialog(Dialog): self.l = l = QVBoxLayout(self) self.edit_note_widget = EditNoteWidget(self.db, self.field, self.item_id, self.item_val, self) l.addWidget(self.edit_note_widget) + self.bb.addButton(_('E&xport'), QDialogButtonBox.ButtonRole.ActionRole).clicked.connect(self.export_note) + self.bb.addButton(_('&Import'), QDialogButtonBox.ButtonRole.ActionRole).clicked.connect(self.import_note) + l.addWidget(self.bb) + def export_note(self): + dest = choose_save_file(self, 'save-exported-note', _('Export note to a file'), filters=[(_('HTML files'), ['html'])], + initial_filename=f'{self.item_val}.html', all_files=False) + if dest: + html = self.edit_note_widget.editor.export_note() + with open(dest, 'wb') as f: + f.write(html.encode('utf-8')) + + def import_note(self): + dest = choose_files(self, 'load-imported-note', _('Import note from a file'), filters=[(_('HTML files'), ['html'])], + all_files=False, select_only_single_file=True) + if dest: + self.edit_note_widget.editor.import_note(dest[0]) + def sizeHint(self): return QSize(800, 620)