camelot.view.controls.editors.richtexteditor — Camelot documentation

### Navigation

- index
- modules |
- Camelot documentation »
- Module code »
- camelot.view.controls.editors »

# Source code for camelot.view.controls.editors.richtexteditor

    #  ============================================================================
    #
    #  Copyright (C) 2007-2011 Conceptive Engineering bvba. All rights reserved.
    #  www.conceptive.be / project-camelot@conceptive.be
    #
    #  This file is part of the Camelot Library.
    #
    #  This file may be used under the terms of the GNU General Public
    #  License version 2.0 as published by the Free Software Foundation
    #  and appearing in the file license.txt included in the packaging of
    #  this file.  Please review this information to ensure GNU
    #  General Public Licensing requirements will be met.
    #
    #  If you are unsure which license is appropriate for your use, please
    #  visit www.python-camelot.com or contact project-camelot@conceptive.be
    #
    #  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    #  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    #
    #  For use of this library in commercial applications, please contact
    #  project-camelot@conceptive.be
    #
    #  ============================================================================

    from PyQt4 import QtGui
    from PyQt4 import QtCore
    from PyQt4.QtCore import Qt
    from wideeditor import WideEditor
    from customeditor import CustomEditor
    from camelot.view.art import Icon

    class CustomTextEdit(QtGui.QTextEdit):
        """
        A TextEdit editor that sends editingFinished events
        when the text was changed and focus is lost.
        """

        editingFinished = QtCore.pyqtSignal()
        receivedFocus = QtCore.pyqtSignal()

        def __init__(self, parent):
            super(CustomTextEdit, self).__init__(parent)
            self._changed = False
            self.setTabChangesFocus( True )
            self.textChanged.connect( self._handle_text_changed )

        def focusInEvent(self, event):
            super(CustomTextEdit, self).focusInEvent( event )
            self.receivedFocus.emit()

        def focusOutEvent(self, event):
            if self._changed:
                self.editingFinished.emit()
            super(CustomTextEdit, self).focusOutEvent( event )

        def _handle_text_changed(self):
            self._changed = True

        def setTextChanged(self, state=True):
            self._changed = state

        def setHtml(self, html):
            QtGui.QTextEdit.setHtml(self, html)
            self._changed = False

    class RichTextEditor(CustomEditor, WideEditor):

        def __init__(self,
                     parent = None,
                     field_name = 'richtext',
                     **kwargs):
            CustomEditor.__init__(self, parent)
            self.setObjectName( field_name )
            self.layout = QtGui.QVBoxLayout(self)
            self.layout.setSpacing(0)
            self.layout.setContentsMargins( 0, 0, 0, 0)
            self.setSizePolicy( QtGui.QSizePolicy.Expanding,
                                QtGui.QSizePolicy.Expanding )

            self.textedit = CustomTextEdit(self)

            self.initToolbar() # Has to be invoked before the connect's below.
            self.toolbar.hide() # Should only be visible when textedit is focused.

            self.textedit.editingFinished.connect(self.emit_editing_finished)
            self.textedit.receivedFocus.connect(self.toolbar.show)
            self.textedit.setAcceptRichText(True)

            # Layout
            self.layout.addWidget(self.toolbar)
            self.layout.addWidget(self.textedit)
            self.setLayout(self.layout)

            # Format
            self.textedit.setFontWeight(QtGui.QFont.Normal)
            self.textedit.setFontItalic(False)
            self.textedit.setFontUnderline(False)
            #self.textedit.setFocus(Qt.OtherFocusReason)
            self.update_alignment()
            self.textedit.currentCharFormatChanged.connect(self.update_format)
            self.textedit.cursorPositionChanged.connect(self.update_text)

        @QtCore.pyqtSlot()
        def emit_editing_finished(self):
            if self.textedit._changed:
                self.editingFinished.emit()

        def set_editable(self, editable):
            self.textedit.setReadOnly(not editable)

        def set_field_attributes(self, editable=True, background_color=None, **kwargs):
            self.set_editable(editable)
            self.set_background_color(background_color)

        def initToolbar(self):
            self.toolbar = QtGui.QToolBar(self)
            self.toolbar.setOrientation(Qt.Horizontal)
            self.toolbar.setContentsMargins(0, 0, 0, 0)

            self.bold_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/format-text-bold.png').getQIcon()
            self.bold_button.setIcon(icon)
            self.bold_button.setAutoRaise(True)
            self.bold_button.setCheckable(True)
            self.bold_button.setFocusPolicy( Qt.ClickFocus )
            self.bold_button.setMaximumSize(QtCore.QSize(20, 20))
            self.bold_button.setShortcut(QtGui.QKeySequence('Ctrl+B'))
            self.bold_button.setToolTip('Bold')
            self.bold_button.clicked.connect(self.set_bold)

            self.italic_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/format-text-italic.png').getQIcon()
            self.italic_button.setIcon(icon)
            self.italic_button.setAutoRaise(True)
            self.italic_button.setCheckable(True)
            self.italic_button.setFocusPolicy( Qt.ClickFocus )
            self.italic_button.setMaximumSize(QtCore.QSize(20, 20))
            self.italic_button.setShortcut(QtGui.QKeySequence('Ctrl+I'))
            self.italic_button.setToolTip('Italic')
            self.italic_button.clicked.connect(self.set_italic)

            self.underline_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/format-text-underline.png').getQIcon()
            self.underline_button.setIcon(icon)
            self.underline_button.setAutoRaise(True)
            self.underline_button.setCheckable(True)
            self.underline_button.setFocusPolicy( Qt.ClickFocus )
            self.underline_button.setMaximumSize(QtCore.QSize(20, 20))
            self.underline_button.setShortcut(QtGui.QKeySequence('Ctrl+U'))
            self.underline_button.setToolTip('Underline')
            self.underline_button.clicked.connect(self.set_underline)

            self.copy_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/edit-copy.png').getQIcon()
            self.copy_button.setIcon(icon)
            self.copy_button.setAutoRaise(True)
            self.copy_button.setMaximumSize(QtCore.QSize(20, 20))
            self.copy_button.setFocusPolicy( Qt.ClickFocus )
            self.copy_button.setToolTip('Copy')
            self.copy_button.clicked.connect(self.textedit.copy)

            self.cut_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/edit-cut.png').getQIcon()
            self.cut_button.setIcon(icon)
            self.cut_button.setAutoRaise(True)
            self.cut_button.setMaximumSize(QtCore.QSize(20, 20))
            self.cut_button.setToolTip('Cut')
            self.cut_button.clicked.connect(self.textedit.cut)
            self.cut_button.setFocusPolicy( Qt.ClickFocus )

            self.paste_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/edit-paste.png').getQIcon()
            self.paste_button.setIcon(icon)
            self.paste_button.setAutoRaise(True)
            self.paste_button.setMaximumSize(QtCore.QSize(20, 20))
            self.paste_button.setFocusPolicy( Qt.ClickFocus )
            self.paste_button.setToolTip('Paste')
            self.paste_button.clicked.connect(self.textedit.paste)

            self.alignleft_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/format-justify-left.png').getQIcon()
            self.alignleft_button.setIcon(icon)
            self.alignleft_button.setAutoRaise(True)
            self.alignleft_button.setCheckable(True)
            self.alignleft_button.setMaximumSize(QtCore.QSize(20, 20))
            self.alignleft_button.setFocusPolicy( Qt.ClickFocus )
            self.alignleft_button.setToolTip('Align left')
            self.alignleft_button.clicked.connect(self.set_alignleft)

            self.aligncenter_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/format-justify-center.png').getQIcon()
            self.aligncenter_button.setIcon(icon)
            self.aligncenter_button.setAutoRaise(True)
            self.aligncenter_button.setCheckable(True)
            self.aligncenter_button.setMaximumSize(QtCore.QSize(20, 20))
            self.aligncenter_button.setFocusPolicy( Qt.ClickFocus )
            self.aligncenter_button.setToolTip('Align Center')
            self.aligncenter_button.clicked.connect(self.set_aligncenter)

            self.alignright_button = QtGui.QToolButton(self)
            icon = Icon('tango/16x16/actions/format-justify-right.png').getQIcon()
            self.alignright_button.setIcon(icon)
            self.alignright_button.setAutoRaise(True)
            self.alignright_button.setCheckable(True)
            self.alignright_button.setMaximumSize(QtCore.QSize(20, 20))
            self.alignright_button.setFocusPolicy( Qt.ClickFocus )
            self.alignright_button.setToolTip('Align Right')
            self.alignright_button.clicked.connect(self.set_alignright)

            self.color_button = QtGui.QToolButton(self)
            self.color_button.setAutoRaise(True)
            self.color_button.setMaximumSize(QtCore.QSize(20, 20))
            self.color_button.setFocusPolicy( Qt.ClickFocus )
            self.color_button.setToolTip('Color')
            self.color_button.clicked.connect(self.set_color)

            self.toolbar.addWidget(self.copy_button)
            self.toolbar.addWidget(self.cut_button)
            self.toolbar.addWidget(self.paste_button)
            self.toolbar.addSeparator()
            self.toolbar.addWidget(self.bold_button)
            self.toolbar.addWidget(self.italic_button)
            self.toolbar.addWidget(self.underline_button)
            self.toolbar.addSeparator()
            self.toolbar.addWidget(self.alignleft_button)
            self.toolbar.addWidget(self.aligncenter_button)
            self.toolbar.addWidget(self.alignright_button)
            self.toolbar.addSeparator()
            self.toolbar.addWidget(self.color_button)

        #
        # Button methods
        #
        def set_bold(self):
            if self.bold_button.isChecked():
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setFontWeight(QtGui.QFont.Bold)
            else:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setFontWeight(QtGui.QFont.Normal)

        def set_italic(self, bool):
            if bool:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setFontItalic(True)
            else:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setFontItalic(False)

        def set_underline(self, bool):
            if bool:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setFontUnderline(True)
            else:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setFontUnderline(False)

        def set_alignleft(self, bool):
            if bool:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setAlignment(Qt.AlignLeft)
            self.update_alignment(Qt.AlignLeft)

        def set_aligncenter(self, bool):
            if bool:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setAlignment(Qt.AlignCenter)
            self.update_alignment(Qt.AlignCenter)

        def set_alignright(self, bool):
            if bool:
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setAlignment(Qt.AlignRight)
            self.update_alignment(Qt.AlignRight)

        def update_alignment(self, al=None):
            if al is None:
                al = self.textedit.alignment()
            if al == Qt.AlignLeft:
                self.alignleft_button.setChecked(True)
                self.aligncenter_button.setChecked(False)
                self.alignright_button.setChecked(False)
            elif al == Qt.AlignCenter:
                self.aligncenter_button.setChecked(True)
                self.alignleft_button.setChecked(False)
                self.alignright_button.setChecked(False)
            elif al == Qt.AlignRight:
                self.alignright_button.setChecked(True)
                self.alignleft_button.setChecked(False)
                self.aligncenter_button.setChecked(False)

        def set_color(self):
            color = QtGui.QColorDialog.getColor(self.textedit.textColor())
            if color.isValid():
                self.textedit.setFocus(Qt.OtherFocusReason)
                self.textedit.setTextColor(color)
                pixmap = QtGui.QPixmap(16, 16)
                pixmap.fill(color)
                self.color_button.setIcon(QtGui.QIcon(pixmap))

        def update_color(self):
            color = self.textedit.textColor()
            pixmap = QtGui.QPixmap(16, 16)
            pixmap.fill(color)
            self.color_button.setIcon(QtGui.QIcon(pixmap))

        def update_format(self, format):
            font = format.font()
            self.bold_button.setChecked(font.bold())
            self.italic_button.setChecked(font.italic())
            self.underline_button.setChecked(font.underline())
            self.update_alignment(self.textedit.alignment())

        def update_text(self):
            self.update_alignment()
            self.update_color()

        def get_value(self):
            from xml.dom import minidom
            tree = minidom.parseString(unicode(self.textedit.toHtml()).encode('utf-8'))
            value = u''.join([node.toxml() for node in tree.getElementsByTagName('html')[0].getElementsByTagName('body')[0].childNodes])
            return CustomEditor.get_value(self) or value

        def set_value(self, value):
            value = CustomEditor.set_value(self, value)
            if value!=None:
                if unicode(self.textedit.toHtml())!=value:
                    self.update_alignment()
                    self.textedit.setHtml(value)
                    self.update_color()
            else:
                self.textedit.clear()

### Navigation

- index
- modules |
- Camelot documentation »
- Module code »
- camelot.view.controls.editors »

Comments
blog comments powered by Disqus