QScintilla/EditorButtonsWidget.py

Sun, 08 Jan 2017 18:52:16 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 08 Jan 2017 18:52:16 +0100
changeset 5407
f833f89571b8
parent 5404
6b19ad5470a3
child 5411
a163fbbf2bea
permissions
-rw-r--r--

Continued implementing a format button bar and provider classes for various markup languages.

# -*- coding: utf-8 -*-

# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a widget containing various buttons for accessing
editor actions.
"""

from __future__ import unicode_literals

from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QToolButton, QFrame, QMenu

import UI.PixmapCache

from . import MarkupProviders


class EditorButtonsWidget(QWidget):
    """
    Class implementing a widget containing various buttons for accessing
    editor actions.
    """
    def __init__(self, editor, parent=None):
        """
        Constructor
        
        @param editor reference to the editor
        @type Editor
        @param parent reference to the parent widget
        @type QWidget
        """
        super(EditorButtonsWidget, self).__init__(parent)
        
        margin = 2
        spacing = 3
        self.__layout = QVBoxLayout(self)
        self.__layout.setContentsMargins(margin, margin, margin, margin)
        self.__layout.setSpacing(spacing)
        
        self.__provider = None
        
        self.__editor = editor
        self.__editor.languageChanged.connect(self.__updateButtonStates)
        self.__editor.editorSaved.connect(self.__updateButtonStates)
        self.__editor.editorRenamed.connect(self.__updateButtonStates)
        self.__editor.selectionChanged.connect(self.__editorSelectionChanged)
        
        self.__createButtons()
        
        self.__layout.addStretch()
        self.setMaximumWidth(
            self.__buttons["bold"].sizeHint().width() + 2 * margin)
        
        self.__updateButtonStates()
    
    def __createButtons(self):
        """
        Private slot to create the various tool buttons.
        """
        self.__buttons = {}
        self.__separators = []
        self.__headerMenu = QMenu()
        
        self.__addButton("bold", "formatTextBold.png",
                         self.tr("Bold"))
        self.__addButton("italic", "formatTextItalic.png",
                         self.tr("Italic"))
        self.__addButton("strikethrough", "formatTextStrikethrough.png",
                         self.tr("Strike Through"))
        self.__addSeparator()
        self.__addButton("header1", "formatTextHeader1.png",
                         self.tr("Header 1"))
        self.__addButton("header2", "formatTextHeader2.png",
                         self.tr("Header 2"))
        self.__addButton("header3", "formatTextHeader3.png",
                         self.tr("Header 3"))
        button = self.__addButton("header", "formatTextHeader.png",
                                  self.tr("Header"))
        button.setPopupMode(QToolButton.InstantPopup)
        button.setMenu(self.__headerMenu)
        self.__addSeparator()
        self.__addButton("code", "formatTextInlineCode.png",
                         self.tr("Inline Code"))
        self.__addButton("codeBlock", "formatTextCodeBlock.png",
                         self.tr("Code Block"))
        self.__addButton("quote", "formatTextQuote.png",
                         self.tr("Quote"))
        self.__addSeparator()
        self.__addButton("hyperlink", "formatTextHyperlink.png",
                         self.tr("Add Hyperlink"))
        self.__addButton("line", "formatTextHorizontalLine.png",
                         self.tr("Add Horizontal Line"))
        self.__addButton("image", "formatTextImage.png",
                         self.tr("Add Image"))
        self.__addSeparator()
        self.__addButton("bulletedList", "formatTextBulletedList.png",
                         self.tr("Add Bulleted List"))
        self.__addButton("numberedList", "formatTextNumberedList.png",
                         self.tr("Add Numbered List"))
        
        self.__headerMenu.triggered.connect(self.__headerMenuTriggered)
    
    def __addButton(self, format, iconName, toolTip):
        """
        Private method to add a format button.
        
        @param format unique name of the format
        @type str
        @param iconName name of the icon for the button
        @type str
        @param toolTip text for the tool tip
        @type str
        @return generated button
        @rtype QToolButton
        """
        button = QToolButton(self)
        button.setIcon(UI.PixmapCache.getIcon(iconName))
        button.setToolTip(toolTip)
        button.clicked.connect(lambda: self.__formatClicked(format))
        self.__layout.addWidget(button)
        self.__buttons[format] = button
        
        return button
    
    def __addSeparator(self):
        """
        Private method to add a separator line.
        """
        line = QFrame(self)
        line.setLineWidth(2)
        if isinstance(self.__layout, QVBoxLayout):
            line.setFrameShape(QFrame.HLine)
        else:
            line.setFrameShape(QFrame.VLine)
        line.setFrameShadow(QFrame.Sunken)
        
        self.__layout.addWidget(line)
        self.__separators.append(line)
    
    @pyqtSlot()
    def __updateButtonStates(self):
        """
        Private slot to change the button states.
        """
        provider = MarkupProviders.getMarkupProvider(self.__editor)
        if self.__provider is None or \
                provider.kind() != self.__provider.kind():
            self.__provider = provider
            
            self.__buttons["bold"].setEnabled(self.__provider.hasBold())
            self.__buttons["italic"].setEnabled(self.__provider.hasItalic())
            self.__buttons["strikethrough"].setEnabled(
                self.__provider.hasStrikethrough())
            
            headerLevels = self.__provider.headerLevels()
            self.__buttons["header1"].setEnabled(headerLevels >= 1)
            self.__buttons["header2"].setEnabled(headerLevels >= 2)
            self.__buttons["header3"].setEnabled(headerLevels >= 3)
            self.__buttons["header"].setEnabled(headerLevels > 3)
            self.__headerMenu.clear()
            for level in range(1, headerLevels + 1):
                act = self.__headerMenu.addAction(
                    self.tr("Level {0}").format(level))
                act.setData("header{0}".format(level))
            
            self.__buttons["code"].setEnabled(self.__provider.hasCode())
            self.__buttons["codeBlock"].setEnabled(
                self.__provider.hasCodeBlock())
            
            self.__editorSelectionChanged()
            
            # TODO: make this configurable
            self.setVisible(self.__provider.kind() != "none")
    
    def __formatClicked(self, format):
        """
        Private slot to handle a format button being clicked.
        
        @param format format type of the button
        @type str
        """
        if format == "bold":
            self.__provider.bold(self.__editor)
        elif format == "italic":
            self.__provider.italic(self.__editor)
        elif format == "strikethrough":
            self.__provider.strikethrough(self.__editor)
        elif format.startswith("header"):
            try:
                level = int(format[-1])
                self.__provider.header(self.__editor, level)
            except ValueError:
                pass
        elif format == "code":
            self.__provider.code(self.__editor)
        elif format == "codeBlock":
            self.__provider.codeBlock(self.__editor)
        elif format == "quote":
            self.__provider.quote(self.__editor)
        elif format == "hyperlink":
            self.__provider.hyperlink(self.__editor)
        elif format == "line":
            self.__provider.line(self.__editor)
        elif format == "image":
            self.__provider.image(self.__editor)
    
    def __headerMenuTriggered(self, act):
        """
        Private method handling the selection of a header menu entry.
        
        @param act action of the headers menu that was triggered
        @type QAction
        """
        format = act.data()
        self.__formatClicked(format)
    
    def __editorSelectionChanged(self):
        """
        Private slot to handle a change of the editor's selection.
        """
        hasSelection = self.__editor.hasSelectedText()
        if self.__provider:
            self.__buttons["quote"].setEnabled(
                self.__provider.hasQuote() and (
                self.__provider.kind() == "html" or hasSelection))
            self.__buttons["hyperlink"].setEnabled(
                self.__provider.hasHyperlink() and not hasSelection)
            self.__buttons["line"].setEnabled(
                self.__provider.hasLine() and not hasSelection)
            self.__buttons["image"].setEnabled(
                self.__provider.hasImage() and not hasSelection)

eric ide

mercurial