From 14bba3eadc9b042c5d9a72f3275f2895d4b0e689 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 16 Dec 2013 16:51:30 +0530 Subject: [PATCH] Edit Book: Add buttons to the editor toolbar to make the selected text bold/italic/superscript/etc. when editing HTML files. --- src/calibre/gui2/tweak_book/boss.py | 5 +++ src/calibre/gui2/tweak_book/editor/text.py | 47 ++++++++++++++++++++ src/calibre/gui2/tweak_book/editor/widget.py | 26 +++++++++++ src/calibre/gui2/tweak_book/ui.py | 5 +++ 4 files changed, 83 insertions(+) diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index e108659e1c..f032a41d6c 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -443,6 +443,11 @@ class Boss(QObject): if ed.has_marked_text: self.gui.central.search_panel.set_where('selected-text') + def editor_action(self, action): + ed = self.gui.central.current_editor + if hasattr(ed, 'action_triggered'): + ed.action_triggered(action) + def show_find(self): self.gui.central.show_find() ed = self.gui.central.current_editor diff --git a/src/calibre/gui2/tweak_book/editor/text.py b/src/calibre/gui2/tweak_book/editor/text.py index 4eb8e0b378..cf19710fbb 100644 --- a/src/calibre/gui2/tweak_book/editor/text.py +++ b/src/calibre/gui2/tweak_book/editor/text.py @@ -161,6 +161,7 @@ class TextEdit(QPlainTextEdit): clipboard.setMimeData(md, clipboard.Selection) def load_text(self, text, syntax='html', process_template=False): + self.syntax = syntax self.highlighter = {'html':HTMLHighlighter, 'css':CSSHighlighter, 'xml':XMLHighlighter}.get(syntax, SyntaxHighlighter)(self) self.highlighter.apply_theme(self.theme) self.highlighter.setDocument(self.document()) @@ -460,3 +461,49 @@ class TextEdit(QPlainTextEdit): ev.ignore() # }}} + def get_range_inside_tag(self): + c = self.textCursor() + left = min(c.anchor(), c.position()) + right = max(c.anchor(), c.position()) + # For speed we use QPlainTextEdit's toPlainText as we dont care about + # spaces in this context + raw = unicode(QPlainTextEdit.toPlainText(self)) + # Make sure the left edge is not within a <> + gtpos = raw.find('>', left) + ltpos = raw.find('<', left) + if gtpos < ltpos: + left = gtpos + 1 if gtpos > -1 else left + right = max(left, right) + if right != left: + gtpos = raw.find('>', right) + ltpos = raw.find('<', right) + if ltpos > gtpos: + ltpos = raw.rfind('<', left, right+1) + right = max(ltpos, left) + return left, right + + def format_text(self, formatting): + if self.syntax != 'html': + return + prefix, suffix = { + 'bold': ('', ''), + 'italic': ('', ''), + 'underline': ('', ''), + 'strikethrough': ('', ''), + 'superscript': ('', ''), + 'subscript': ('', ''), + }[formatting] + left, right = self.get_range_inside_tag() + c = self.textCursor() + c.setPosition(left) + c.setPosition(right, c.KeepAnchor) + prev_text = unicode(c.selectedText()) + c.insertText(prefix + prev_text + suffix) + if prev_text: + right = c.position() + c.setPosition(left) + c.setPosition(right, c.KeepAnchor) + else: + c.setPosition(c.position() - len(suffix)) + self.setTextCursor(c) + diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py index 5fa7905498..22335a42dd 100644 --- a/src/calibre/gui2/tweak_book/editor/widget.py +++ b/src/calibre/gui2/tweak_book/editor/widget.py @@ -14,6 +14,23 @@ from calibre.gui2 import error_dialog from calibre.gui2.tweak_book import actions, current_container from calibre.gui2.tweak_book.editor.text import TextEdit +def register_text_editor_actions(reg): + ac = reg('format-text-bold', _('&Bold'), ('format_text', 'bold'), 'format-text-bold', 'Ctrl+B', _('Make the selected text bold')) + ac.setToolTip(_('

Bold

Make the selected text bold')) + ac = reg('format-text-italic', _('&Italic'), ('format_text', 'italic'), 'format-text-italic', 'Ctrl+I', _('Make the selected text italic')) + ac.setToolTip(_('

Italic

Make the selected text italic')) + ac = reg('format-text-underline', _('&Underline'), ('format_text', 'underline'), 'format-text-underline', (), _('Underline the selected text')) + ac.setToolTip(_('

Underline

Underline the selected text')) + ac = reg('format-text-strikethrough', _('&Strikethrough'), ('format_text', 'strikethrough'), + 'format-text-strikethrough', (), _('Draw a line through the selected text')) + ac.setToolTip(_('

Strikethrough

Draw a line through the selected text')) + ac = reg('format-text-superscript', _('&Superscript'), ('format_text', 'superscript'), + 'format-text-superscript', (), _('Make the selected text a superscript')) + ac.setToolTip(_('

Superscript

Set the selected text slightly smaller and above the normal line')) + ac = reg('format-text-subscript', _('&Subscript'), ('format_text', 'subscript'), + 'format-text-subscript', (), _('Make the selected text a subscript')) + ac.setToolTip(_('

Subscript

Set the selected text slightly smaller and below the normal line')) + class Editor(QMainWindow): has_line_numbers = True @@ -83,6 +100,11 @@ class Editor(QMainWindow): def set_focus(self): self.editor.setFocus(Qt.OtherFocusReason) + def action_triggered(self, action): + action, args = action[0], action[1:] + func = getattr(self.editor, action) + func(*args) + def undo(self): self.editor.undo() @@ -135,6 +157,10 @@ class Editor(QMainWindow): b.addAction(actions['fix-html-current']) if self.syntax in {'xml', 'html', 'css'}: b.addAction(actions['pretty-current']) + if self.syntax == 'html': + self.format_bar = b = self.addToolBar(_('Format text')) + for x in ('bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript'): + b.addAction(actions['format-text-%s' % x]) def break_cycles(self): self.modification_state_changed.disconnect() diff --git a/src/calibre/gui2/tweak_book/ui.py b/src/calibre/gui2/tweak_book/ui.py index a22db6a7b7..4462bc2d46 100644 --- a/src/calibre/gui2/tweak_book/ui.py +++ b/src/calibre/gui2/tweak_book/ui.py @@ -28,6 +28,7 @@ from calibre.gui2.tweak_book.preview import Preview from calibre.gui2.tweak_book.search import SearchPanel from calibre.gui2.tweak_book.check import Check from calibre.gui2.tweak_book.toc import TOCViewer +from calibre.gui2.tweak_book.editor.widget import register_text_editor_actions def open_donate(): open_url(QUrl('http://calibre-ebook.com/donate')) @@ -290,6 +291,10 @@ class Main(MainWindow): self.action_editor_undo.setEnabled(False) self.action_editor_redo.setEnabled(False) + def ereg(icon, text, target, sid, keys, description): + return reg(icon, text, partial(self.boss.editor_action, target), sid, keys, description) + register_text_editor_actions(ereg) + # Tool actions group = _('Tools') self.action_toc = reg('toc.png', _('&Edit Table of Contents'), self.boss.edit_toc, 'edit-toc', (), _('Edit Table of Contents'))