Enhancement #2017403: Add a preview tab to Markdown "long text" editor (https://bugs.launchpad.net/calibre/+bug/2017403)

This commit is contained in:
un-pogaz 2023-04-25 18:15:53 +02:00
parent 6c9bd54cb6
commit b990609ac1
2 changed files with 161 additions and 1 deletions

View File

@ -18,6 +18,7 @@ from qt.core import (
from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata import title_sort
from calibre.gui2 import UNDEFINED_QDATETIME, elided_text, error_dialog, gprefs from calibre.gui2 import UNDEFINED_QDATETIME, elided_text, error_dialog, gprefs
from calibre.gui2.comments_editor import Editor as CommentsEditor from calibre.gui2.comments_editor import Editor as CommentsEditor
from calibre.gui2.markdown_editor import Editor as MarkdownEditor
from calibre.gui2.complete2 import EditWithComplete as EWC from calibre.gui2.complete2 import EditWithComplete as EWC
from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.gui2.dialogs.tag_editor import TagEditor
from calibre.gui2.library.delegates import ClearingDoubleSpinBox, ClearingSpinBox from calibre.gui2.library.delegates import ClearingDoubleSpinBox, ClearingSpinBox
@ -467,6 +468,41 @@ class Comments(Base):
self.signals_to_disconnect.append(self._tb.data_changed) self.signals_to_disconnect.append(self._tb.data_changed)
class Markdown(Base):
def setup_ui(self, parent):
self._box = QGroupBox(parent)
self._box.setTitle(label_string(self.col_metadata['name']))
self._layout = QVBoxLayout()
self._tb = MarkdownEditor(self._box)
self._tb.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
# self._tb.setTabChangesFocus(True)
self._layout.addWidget(self._tb)
self._box.setLayout(self._layout)
self.widgets = [self._box]
def setter(self, val):
self._tb.markdown = str(val or '').strip()
def getter(self):
val = self._tb.markdown.strip()
if not val:
val = None
return val
@property
def tab(self):
return self._tb.tab
@tab.setter
def tab(self, val):
self._tb.tab = val
def connect_data_changed(self, slot):
self._tb.editor.textChanged.connect(slot)
self.signals_to_disconnect.append(self._tb.editor.textChanged)
class MultipleWidget(QWidget): class MultipleWidget(QWidget):
def __init__(self, parent, only_manage_items=False, widget=EditWithComplete, name=None): def __init__(self, parent, only_manage_items=False, widget=EditWithComplete, name=None):
@ -780,8 +816,10 @@ def comments_factory(db, key, parent):
ctype = fm.get('display', {}).get('interpret_as', 'html') ctype = fm.get('display', {}).get('interpret_as', 'html')
if ctype == 'short-text': if ctype == 'short-text':
return SimpleText(db, key, parent) return SimpleText(db, key, parent)
if ctype in ('long-text', 'markdown'): if ctype == 'long-text':
return LongText(db, key, parent) return LongText(db, key, parent)
if ctype == 'markdown':
return Markdown(db, key, parent)
return Comments(db, key, parent) return Comments(db, key, parent)

View File

@ -0,0 +1,122 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2023, un_pogaz <un.pogaz@gmail.com>'
__docformat__ = 'restructuredtext en'
from qt.core import (
QPlainTextEdit, Qt, QTabWidget, QVBoxLayout, QWidget,
)
from calibre.gui2.book_details import css
from calibre.gui2.widgets2 import HTMLDisplay
from calibre.library.comments import markdown
class Editor(QWidget): # {{{
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self._layout = QVBoxLayout(self)
self.setLayout(self._layout)
self.tabs = QTabWidget(self)
self.tabs.setTabPosition(QTabWidget.TabPosition.South)
self._layout.addWidget(self.tabs)
self.editor = QPlainTextEdit(self.tabs)
self.preview = HTMLDisplay(self.tabs)
self.preview.setDefaultStyleSheet(css())
self.preview.setTabChangesFocus(True)
self.tabs.addTab(self.editor, _('&Markdown source'))
self.tabs.addTab(self.preview, _('&Preview'))
self.tabs.currentChanged[int].connect(self.change_tab)
self.layout().setContentsMargins(0, 0, 0, 0)
def set_minimum_height_for_editor(self, val):
self.editor.setMinimumHeight(val)
@property
def markdown(self):
self.tabs.setCurrentIndex(0)
return self.editor.toPlainText().strip()
@markdown.setter
def markdown(self, v):
self.editor.setPlainText(str(v or ''))
def change_tab(self, index):
if index == 0: # changing to source
pass
if index == 1: # changing to preview
html = markdown(self.editor.toPlainText().strip())
val = f'''\
<html>
<head></head>
<body class="vertical">
<div>{html}</div>
</body>
<html>'''
self.preview.setHtml(val)
@property
def tab(self):
return 'code' if self.tabs.currentWidget() is self.editor else 'preview'
@tab.setter
def tab(self, val):
self.tabs.setCurrentWidget(self.preview if val == 'preview' else self.editor)
def set_readonly(self, val):
self.editor.setReadOnly(bool(val))
def hide_tabs(self):
self.tabs.tabBar().setVisible(False)
def smarten_punctuation(self):
from calibre.ebooks.conversion.preprocess import smarten_punctuation
markdown = self.markdown
newmarkdown = smarten_punctuation(markdown)
if markdown != newmarkdown:
self.markdown = newmarkdown
# }}}
if __name__ == '__main__':
from calibre.gui2 import Application
app = Application([])
w = Editor()
w.resize(800, 600)
w.setWindowFlag(Qt.WindowType.Dialog)
w.show()
w.markdown = '''\
test *italic* **bold** ***bold-italic*** `code` [link](https://calibre-ebook.com) <span style="font-weight: bold; color:red">span</span>
> Blockquotes
if '>'+' '*4 in string:
pre_block()
1. list 1
1. list 1.1
2. list 1.2
2. list 2
***
* list
- list
# Headers 1
## Headers 2
### Headers 3
#### Headers 4
##### Headers 5
###### Headers 6
'''
app.exec()
# print(w.markdown)