Refactor for better code organization

This commit is contained in:
Kovid Goyal 2015-01-09 14:10:19 +05:30
parent b564245480
commit 08a536ff48
4 changed files with 86 additions and 89 deletions

View File

@ -19,7 +19,7 @@ from PyQt5.Qt import (
from calibre.gui2 import error_dialog from calibre.gui2 import error_dialog
from calibre.gui2.tweak_book.editor import all_text_syntaxes from calibre.gui2.tweak_book.editor import all_text_syntaxes
from calibre.gui2.tweak_book.editor.smarts.utils import get_text_before_cursor from calibre.gui2.tweak_book.editor.smarts.utils import get_text_before_cursor
from calibre.gui2.tweak_book.widgets import Dialog from calibre.gui2.tweak_book.widgets import Dialog, PlainTextEdit
from calibre.utils.config import JSONConfig from calibre.utils.config import JSONConfig
from calibre.utils.icu import string_length as strlen from calibre.utils.icu import string_length as strlen
@ -413,6 +413,19 @@ class SnippetManager(QObject):
# Config {{{ # Config {{{
class SnippetTextEdit(PlainTextEdit):
def __init__(self, text, parent=None):
PlainTextEdit.__init__(self, parent)
if text:
self.setPlainText(text)
self.snippet_manager = SnippetManager(self)
def keyPressEvent(self, ev):
if self.snippet_manager.handle_key_press(ev):
return
PlainTextEdit.keyPressEvent(self, ev)
class EditSnippet(QWidget): class EditSnippet(QWidget):
def __init__(self, parent=None): def __init__(self, parent=None):
@ -451,11 +464,10 @@ class EditSnippet(QWidget):
add_row(_('&File types:'), t) add_row(_('&File types:'), t)
t.setToolTip(_('Which file types this snippet should be active in')) t.setToolTip(_('Which file types this snippet should be active in'))
from calibre.gui2.tweak_book.search import TextEdit
self.frame = f = QFrame(self) self.frame = f = QFrame(self)
f.setFrameShape(f.HLine) f.setFrameShape(f.HLine)
add_row(f) add_row(f)
self.test = d = TextEdit('', self) self.test = d = SnippetTextEdit('', self)
d.snippet_manager.snip_func = self.snip_func d.snippet_manager.snip_func = self.snip_func
d.setToolTip(_('You can test your snippet here')) d.setToolTip(_('You can test your snippet here'))
d.setMaximumHeight(t.maximumHeight() + 15) d.setMaximumHeight(t.maximumHeight() + 15)

View File

@ -13,8 +13,8 @@ from future_builtins import map
import regex import regex
from PyQt5.Qt import ( from PyQt5.Qt import (
QPlainTextEdit, QFontDatabase, QToolTip, QPalette, QFont, QKeySequence, QPlainTextEdit, QFontDatabase, QToolTip, QPalette, QFont, QKeySequence,
QTextEdit, QTextFormat, QWidget, QSize, QPainter, Qt, QRect, pyqtSlot, QTextEdit, QTextFormat, QWidget, QSize, QPainter, Qt, QRect, QColor,
QApplication, QMimeData, QColor, QColorDialog, QTimer, pyqtSignal, QT_VERSION) QColorDialog, QTimer, pyqtSignal, QT_VERSION)
from calibre import prepare_string_for_xml from calibre import prepare_string_for_xml
from calibre.constants import isosx from calibre.constants import isosx
@ -26,14 +26,11 @@ from calibre.gui2.tweak_book.editor.themes import get_theme, theme_color, theme_
from calibre.gui2.tweak_book.editor.syntax.base import SyntaxHighlighter from calibre.gui2.tweak_book.editor.syntax.base import SyntaxHighlighter
from calibre.gui2.tweak_book.editor.smarts import NullSmarts from calibre.gui2.tweak_book.editor.smarts import NullSmarts
from calibre.gui2.tweak_book.editor.snippets import SnippetManager from calibre.gui2.tweak_book.editor.snippets import SnippetManager
from calibre.gui2.tweak_book.widgets import PlainTextEdit, PARAGRAPH_SEPARATOR
from calibre.spell.break_iterator import index_of from calibre.spell.break_iterator import index_of
from calibre.utils.icu import safe_chr, string_length, capitalize, upper, lower, swapcase from calibre.utils.icu import safe_chr, string_length, capitalize, upper, lower, swapcase
from calibre.utils.titlecase import titlecase from calibre.utils.titlecase import titlecase
PARAGRAPH_SEPARATOR = '\u2029'
def selected_text_from_cursor(cursor):
return unicodedata.normalize('NFC', unicode(cursor.selectedText()).replace(PARAGRAPH_SEPARATOR, '\n').rstrip('\0'))
def get_highlighter(syntax): def get_highlighter(syntax):
if syntax: if syntax:
@ -76,67 +73,6 @@ class LineNumbers(QWidget): # {{{
self.parent().paint_line_numbers(ev) self.parent().paint_line_numbers(ev)
# }}} # }}}
class PlainTextEdit(QPlainTextEdit):
''' A class that overrides some methods from QPlainTextEdit to fix handling
of the nbsp unicode character. '''
def __init__(self, parent=None):
QPlainTextEdit.__init__(self, parent)
self.selectionChanged.connect(self.selection_changed)
self.syntax = None
def toPlainText(self):
# QPlainTextEdit's toPlainText implementation replaces nbsp with normal
# space, so we re-implement it using QTextCursor, which does not do
# that
c = self.textCursor()
c.clearSelection()
c.movePosition(c.Start)
c.movePosition(c.End, c.KeepAnchor)
ans = c.selectedText().replace(PARAGRAPH_SEPARATOR, '\n')
# QTextCursor pads the return value of selectedText with null bytes if
# non BMP characters such as 0x1f431 are present.
return ans.rstrip('\0')
@pyqtSlot()
def copy(self):
# Workaround Qt replacing nbsp with normal spaces on copy
c = self.textCursor()
if not c.hasSelection():
return
md = QMimeData()
md.setText(self.selected_text)
QApplication.clipboard().setMimeData(md)
@pyqtSlot()
def cut(self):
# Workaround Qt replacing nbsp with normal spaces on copy
self.copy()
self.textCursor().removeSelectedText()
def selected_text_from_cursor(self, cursor):
return selected_text_from_cursor(cursor)
@property
def selected_text(self):
return self.selected_text_from_cursor(self.textCursor())
def selection_changed(self):
# Workaround Qt replacing nbsp with normal spaces on copy
clipboard = QApplication.clipboard()
if clipboard.supportsSelection() and self.textCursor().hasSelection():
md = QMimeData()
md.setText(self.selected_text)
clipboard.setMimeData(md, clipboard.Selection)
def event(self, ev):
if ev.type() == ev.ShortcutOverride and ev in (QKeySequence.Copy, QKeySequence.Cut):
ev.accept()
(self.copy if ev == QKeySequence.Copy else self.cut)()
return True
return QPlainTextEdit.event(self, ev)
class TextEdit(PlainTextEdit): class TextEdit(PlainTextEdit):
link_clicked = pyqtSignal(object) link_clicked = pyqtSignal(object)

View File

@ -26,8 +26,7 @@ from calibre.gui2.tweak_book import tprefs, editors, current_container
from calibre.gui2.tweak_book.function_replace import ( from calibre.gui2.tweak_book.function_replace import (
FunctionBox, functions as replace_functions, FunctionEditor, remove_function, Function) FunctionBox, functions as replace_functions, FunctionEditor, remove_function, Function)
from calibre.gui2.tweak_book.widgets import BusyCursor from calibre.gui2.tweak_book.widgets import BusyCursor
from calibre.gui2.tweak_book.editor.text import PlainTextEdit from calibre.gui2.tweak_book.editor.snippets import find_matching_snip, parse_template, string_length, SnippetTextEdit
from calibre.gui2.tweak_book.editor.snippets import find_matching_snip, parse_template, string_length, SnippetManager
from calibre.utils.icu import primary_contains from calibre.utils.icu import primary_contains
@ -53,19 +52,6 @@ class AnimatablePushButton(QPushButton):
self.setDown(False) self.setDown(False)
self.update() self.update()
class TextEdit(PlainTextEdit):
def __init__(self, text, parent=None):
PlainTextEdit.__init__(self, parent)
if text:
self.setPlainText(text)
self.snippet_manager = SnippetManager(self)
def keyPressEvent(self, ev):
if self.snippet_manager.handle_key_press(ev):
return
PlainTextEdit.keyPressEvent(self, ev)
class PushButton(AnimatablePushButton): class PushButton(AnimatablePushButton):
def __init__(self, text, action, parent): def __init__(self, text, action, parent):
@ -594,12 +580,12 @@ class EditSearch(QFrame): # {{{
h.addWidget(la), h.addWidget(n) h.addWidget(la), h.addWidget(n)
l.addLayout(h) l.addLayout(h)
self.find = f = TextEdit('', self) self.find = f = SnippetTextEdit('', self)
self.la2 = la = QLabel(_('&Find:')) self.la2 = la = QLabel(_('&Find:'))
la.setBuddy(f) la.setBuddy(f)
l.addWidget(la), l.addWidget(f) l.addWidget(la), l.addWidget(f)
self.replace = r = TextEdit('', self) self.replace = r = SnippetTextEdit('', self)
self.la3 = la = QLabel(_('&Replace:')) self.la3 = la = QLabel(_('&Replace:'))
la.setBuddy(r) la.setBuddy(r)
l.addWidget(la), l.addWidget(r) l.addWidget(la), l.addWidget(r)

View File

@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
import os, textwrap import os, textwrap, unicodedata
from itertools import izip from itertools import izip
from collections import OrderedDict from collections import OrderedDict
@ -16,7 +16,7 @@ from PyQt5.Qt import (
QPainter, QStaticText, pyqtSignal, QTextOption, QAbstractListModel, QPainter, QStaticText, pyqtSignal, QTextOption, QAbstractListModel,
QModelIndex, QStyledItemDelegate, QStyle, QCheckBox, QListView, QModelIndex, QStyledItemDelegate, QStyle, QCheckBox, QListView,
QTextDocument, QSize, QComboBox, QFrame, QCursor, QGroupBox, QSplitter, QTextDocument, QSize, QComboBox, QFrame, QCursor, QGroupBox, QSplitter,
QPixmap, QRect) QPixmap, QRect, QPlainTextEdit, pyqtSlot, QMimeData, QKeySequence)
from calibre import prepare_string_for_xml, human_readable from calibre import prepare_string_for_xml, human_readable
from calibre.ebooks.oeb.polish.utils import lead_text, guess_type from calibre.ebooks.oeb.polish.utils import lead_text, guess_type
@ -28,6 +28,7 @@ from calibre.utils.matcher import get_char, Matcher
from calibre.gui2.complete2 import EditWithComplete from calibre.gui2.complete2 import EditWithComplete
ROOT = QModelIndex() ROOT = QModelIndex()
PARAGRAPH_SEPARATOR = '\u2029'
class BusyCursor(object): class BusyCursor(object):
@ -1111,6 +1112,68 @@ class AddCover(Dialog):
# }}} # }}}
class PlainTextEdit(QPlainTextEdit): # {{{
''' A class that overrides some methods from QPlainTextEdit to fix handling
of the nbsp unicode character. '''
def __init__(self, parent=None):
QPlainTextEdit.__init__(self, parent)
self.selectionChanged.connect(self.selection_changed)
self.syntax = None
def toPlainText(self):
# QPlainTextEdit's toPlainText implementation replaces nbsp with normal
# space, so we re-implement it using QTextCursor, which does not do
# that
c = self.textCursor()
c.clearSelection()
c.movePosition(c.Start)
c.movePosition(c.End, c.KeepAnchor)
ans = c.selectedText().replace(PARAGRAPH_SEPARATOR, '\n')
# QTextCursor pads the return value of selectedText with null bytes if
# non BMP characters such as 0x1f431 are present.
return ans.rstrip('\0')
@pyqtSlot()
def copy(self):
# Workaround Qt replacing nbsp with normal spaces on copy
c = self.textCursor()
if not c.hasSelection():
return
md = QMimeData()
md.setText(self.selected_text)
QApplication.clipboard().setMimeData(md)
@pyqtSlot()
def cut(self):
# Workaround Qt replacing nbsp with normal spaces on copy
self.copy()
self.textCursor().removeSelectedText()
def selected_text_from_cursor(self, cursor):
return unicodedata.normalize('NFC', unicode(cursor.selectedText()).replace(PARAGRAPH_SEPARATOR, '\n').rstrip('\0'))
@property
def selected_text(self):
return self.selected_text_from_cursor(self.textCursor())
def selection_changed(self):
# Workaround Qt replacing nbsp with normal spaces on copy
clipboard = QApplication.clipboard()
if clipboard.supportsSelection() and self.textCursor().hasSelection():
md = QMimeData()
md.setText(self.selected_text)
clipboard.setMimeData(md, clipboard.Selection)
def event(self, ev):
if ev.type() == ev.ShortcutOverride and ev in (QKeySequence.Copy, QKeySequence.Cut):
ev.accept()
(self.copy if ev == QKeySequence.Copy else self.cut)()
return True
return QPlainTextEdit.event(self, ev)
# }}}
if __name__ == '__main__': if __name__ == '__main__':
app = QApplication([]) app = QApplication([])
AddCover.test() AddCover.test()