Exemple #1
0
    def paintEvent(self, event):
        painter = QPainter(self)

        metrics = QFontMetrics(self.font())
        elided = metrics.elidedText(self.text(), Qt.ElideRight, self.width())

        painter.drawText(self.rect(), self.alignment(), elided)
    def paintEvent( self, event ):
        painter = QPainter(self)

        metrics = QFontMetrics(self.font())
        elided  = metrics.elidedText(self.text(), QtCore.Qt.ElideLeft, self.width())

        painter.drawText(self.rect(), self.alignment(), elided)
Exemple #3
0
 def __getElidedText(self,font,s,maxWidth):
     '''
     '''
     fontWidth = QFontMetrics(font)
     width = fontWidth.width(s)
     if width >= maxWidth:
         s = fontWidth.elidedText(s,Qt.ElideRight,maxWidth)
     return s
 def _drawEntryRow(self, painter, option, index):
     """ Отрисовка строки с записью """
     fontColor = Qt.black
     if option.state & QStyle.State_Selected:
         painter.fillRect(option.rect, option.palette.highlight())
         fontColor = Qt.white
     elif settings.useAlternateRowColors() and index.row() % 2 == 1:
         painter.fillRect(option.rect, QColor('#DDEBFF'))
     indexIsNotLastInCategory = index.sibling(index.row() + 1, index.column()).isValid()
     if indexIsNotLastInCategory:
         painter.setPen(QColor(250, 250, 250))
         painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
     iconHeight = settings.entryIconHeight()
     if settings.oneLineEntry():
         y = (option.rect.height() - iconHeight) / 2
     else:
         y = settings.entryTopBottomMargin()
     iconPoint = QPoint(option.rect.left(), option.rect.top() + y)
     if index.data(Qt.CheckStateRole):
         painter.drawPixmap(iconPoint, QPixmap(":/icons/interesting.svg"))
     else:
         painter.drawPixmap(iconPoint, QPixmap(":/icons/boring.svg"))
     painter.setFont(index.data(Qt.FontRole))
     painter.setPen(fontColor)
     baseLine = (option.rect.height() + option.fontMetrics.ascent()) / 2
     blog, title = tuple(i.strip() for i in index.data().split("/", 1))
     fontMetrics = QFontMetrics(index.data(Qt.FontRole))
     totalWidth = option.rect.width()
     iconWidth = settings.entryIconWidth() + settings.entryLeftMargin()
     blogWidth = fontMetrics.width(blog)
     titleWidth = totalWidth - iconWidth - blogWidth
     if settings.oneLineEntry():
         textY = blogY = option.rect.top() + baseLine
         textX = option.rect.left() + iconWidth
         blogX = option.rect.right() - blogWidth
         elidedTitle = fontMetrics.elidedText(title, Qt.ElideRight, titleWidth)
     else:
         textX = blogX = option.rect.left() + iconWidth
         textY = option.rect.top() + 2 * fontMetrics.ascent()
         blogY = option.rect.top() + fontMetrics.ascent()
         elidedTitle = fontMetrics.elidedText(title, Qt.ElideRight, totalWidth - iconWidth)
     painter.drawText(textX, textY, elidedTitle)
     painter.setPen(Qt.lightGray)
     painter.drawText(blogX, blogY, blog)
 def resizeEvent( self, event ):
     super(VersionItemWidget,self).resizeEvent(event)
     
     # make sure we have finished initializing before we resize
     if ( not '_version' in self.__dict__ ):
         return
         
     metrics = QFontMetrics(self.font())
     version = self._version
     
     # update the labels with eliding based on new spacing
     self.uiUserLBL.setText(         metrics.elidedText( version.username(),                     Qt.ElideRight, self.uiUserLBL.width() ) )
     
     # convert out any html data
     comments = str(version.comments())
     doc = QTextDocument()
     doc.setHtml(comments)
     comments = str(doc.toPlainText())
     
     self.uiCommentsLBL.setText(     metrics.elidedText( comments.replace('\n',' '),   Qt.ElideRight, self.uiCommentsLBL.width() ) )
Exemple #6
0
    def paintEvent(self, event):
        """
        Overloads the paint event to paint additional \
        hint information if no text is set on the \
        editor.
        
        :param      event      | <QPaintEvent>
        """
        super(XLineEdit, self).paintEvent(event)

        # paint the hint text if not text is set
        if self.text() and not (self.icon() and not self.icon().isNull()):
            return

        # paint the hint text
        painter = QPainter(self)
        painter.setPen(self.hintColor())

        icon = self.icon()
        left, top, right, bottom = self.getTextMargins()

        w = self.width()
        h = self.height() - 2

        w -= (right + left)
        h -= (bottom + top)

        if icon and not icon.isNull():
            size = icon.actualSize(self.iconSize())
            x = 5 + left
            y = (self.height() - size.height()) / 2.0

            painter.drawPixmap(x, y, icon.pixmap(size.width(), size.height()))

            w -= size.width() - 2
        else:
            x = 6 + left

        w -= sum([btn.width() for btn in self.buttons()])
        y = 2 + top

        # create the elided hint
        if not self.text() and self.hint():
            rect = self.cursorRect()
            metrics = QFontMetrics(self.font())
            hint = metrics.elidedText(self.hint(), Qt.ElideRight, w)
            align = self.alignment()

            if align & Qt.AlignHCenter:
                x = 0
            else:
                x = rect.center().x()

            painter.drawText(x, y, w, h, align, hint)
Exemple #7
0
 def paintEvent( self, event ):
     """
     Overloads the paint event to paint additional \
     hint information if no text is set on the \
     editor.
     
     :param      event      | <QPaintEvent>
     """
     super(XLineEdit, self).paintEvent(event)
     
     # paint the hint text if not text is set
     if self.text() and not (self.icon() and not self.icon().isNull()):
         return
     
     # paint the hint text
     painter = QPainter(self)
     painter.setPen(self.hintColor())
     
     icon = self.icon()
     left, top, right, bottom = self.getTextMargins()
     
     w = self.width()
     h = self.height() - 2
     
     w -= (right + left)
     h -= (bottom + top)
     
     if icon and not icon.isNull():
         size = icon.actualSize(self.iconSize())
         x    = 5 + left
         y    = (self.height() - size.height()) / 2.0
         
         painter.drawPixmap(x, y, icon.pixmap(size.width(), size.height()))
         
         w -= size.width() - 2
     else:
         x = 6 + left
     
     w -= sum([btn.width() for btn in self.buttons()])
     y = 2 + top
     
     # create the elided hint
     if not self.text() and self.hint():
         rect    = self.cursorRect()
         metrics = QFontMetrics(self.font())
         hint    = metrics.elidedText(self.hint(), Qt.ElideRight, w)
         align   = self.alignment()
         
         if align & Qt.AlignHCenter:
             x = 0
         else:
             x = rect.center().x()
         
         painter.drawText(x, y, w, h, align, hint)
Exemple #8
0
    def __textLayout(self):
        fm = QFontMetrics(self.font())
        text = str(self.defaultAction().text())
        words = deque(text.split())

        lines = []
        curr_line = ""
        curr_line_word_count = 0

        option = QStyleOptionToolButton()
        option.initFrom(self)

        margin = self.style().pixelMetric(QStyle.PM_ButtonMargin, option, self)
        width = self.width() - 2 * margin

        while words:
            w = words.popleft()

            if curr_line_word_count:
                line_extended = " ".join([curr_line, w])
            else:
                line_extended = w

            line_w = fm.boundingRect(line_extended).width()

            if line_w >= width:
                if curr_line_word_count == 0 or len(lines) == 1:
                    # A single word that is too long must be elided.
                    # Also if the text overflows 2 lines
                    # Warning: hardcoded max lines
                    curr_line = fm.elidedText(line_extended, Qt.ElideRight,
                                              width)
                    curr_line = str(curr_line)
                else:
                    # Put the word back
                    words.appendleft(w)

                lines.append(curr_line)
                curr_line = ""
                curr_line_word_count = 0
                if len(lines) == 2:
                    break
            else:
                curr_line = line_extended
                curr_line_word_count += 1

        if curr_line:
            lines.append(curr_line)

        text = "\n".join(lines)
        text = text.replace('&', '&&')  # Need escaped ampersand to show

        self.__text = text
Exemple #9
0
    def resizeEvent(self, event):
        super(VersionItemWidget, self).resizeEvent(event)

        # make sure we have finished initializing before we resize
        if (not '_version' in self.__dict__):
            return

        metrics = QFontMetrics(self.font())
        version = self._version

        # update the labels with eliding based on new spacing
        self.uiUserLBL.setText(
            metrics.elidedText(version.username(), Qt.ElideRight,
                               self.uiUserLBL.width()))

        # convert out any html data
        comments = str(version.comments())
        doc = QTextDocument()
        doc.setHtml(comments)
        comments = str(doc.toPlainText())

        self.uiCommentsLBL.setText(
            metrics.elidedText(comments.replace('\n', ' '), Qt.ElideRight,
                               self.uiCommentsLBL.width()))
Exemple #10
0
 def paintEvent(self, event):
     QLineEdit.paintEvent(self, event)
     if not self.text() and self.placeholderText() and \
             not self.hasFocus():
         p = QStylePainter(self)
         font = self.font()
         metrics = QFontMetrics(font)
         p.setFont(font)
         color = self.palette().color(QPalette.Mid)
         p.setPen(color)
         left, top, right, bottom = self.getTextMargins()
         contents = self.contentsRect()
         contents = contents.adjusted(left, top, -right, -bottom)
         text = metrics.elidedText(self.placeholderText(),
                                   Qt.ElideMiddle,
                                   contents.width())
         p.drawText(contents, Qt.AlignLeft | Qt.AlignVCenter, text)
Exemple #11
0
 def renderCell(self, painter, rowStats, colStats, itemRect):
     rowIndex = rowStats.index
     colIndex = colStats.index if colStats is not None else 0
     extraFlags = nonone(self.ds.data(rowIndex, colIndex, EXTRA_ROLE), 0)
     pixmap = self.ds.data(rowIndex, colIndex, Qt.DecorationRole)
     if pixmap:
         painter.drawPixmap(itemRect.topLeft(), pixmap)
     else:
         # we don't support drawing pixmap and text in the same cell (don't need it)
         bgbrush = self.ds.data(rowIndex, colIndex, Qt.BackgroundRole)
         if bgbrush is not None:
             painter.fillRect(itemRect, bgbrush)
         if rowStats.splitCount > 2 and colStats.col.name in {'from', 'to', 'transfer'}:
             text = '--split--'
         else:
             text = self.ds.data(rowIndex, colIndex, Qt.DisplayRole)
         if text:
             alignment = self.ds.data(rowIndex, colIndex, Qt.TextAlignmentRole)
             if not alignment:
                 alignment = Qt.AlignLeft|Qt.AlignVCenter
             font = self.ds.data(rowIndex, colIndex, Qt.FontRole)
             if font is None:
                 font = self.ds.rowFont()
             fm = QFontMetrics(font)
             # elidedText has a tendency to "over-elide" that's why we have "+1"
             text = fm.elidedText(text, Qt.ElideRight, itemRect.width()+1)
             painter.save()
             painter.setFont(font)
             painter.drawText(itemRect, alignment, text)
             painter.restore()
     if extraFlags & (EXTRA_UNDERLINED | EXTRA_UNDERLINED_DOUBLE):
         p1 = itemRect.bottomLeft()
         p2 = itemRect.bottomRight()
         # Things get crowded with double lines and we have to cheat a little bit on 
         # item rects.
         p1.setY(p1.y()+2)
         p2.setY(p2.y()+2)
         painter.drawLine(p1, p2)
         if extraFlags & EXTRA_UNDERLINED_DOUBLE:
             p1.setY(p1.y()-3)
             p2.setY(p2.y()-3)
             painter.drawLine(p1, p2)
Exemple #12
0
 def paintEvent(self, event ):
     """QLineEdit.paintEvent implementation.
     Draws prompt
     """
     QLineEdit.paintEvent( self, event )
     
     if self._promptText and not self.text() and self.isEnabled() :
         option = QStyleOptionFrameV3()
         self.initStyleOption( option )
         
         left, top, right, bottom = self.getTextMargins()
         
         va = self.style().visualAlignment( self.layoutDirection(), self.alignment() )
         rect = self.style().subElementRect( 
             QStyle.SE_LineEditContents, option, self ).adjusted( 2, 0, 0, 0 ).adjusted( left, top, -right, -bottom )
         fm = QFontMetrics ( self.font() )
         text = fm.elidedText( self._promptText, Qt.ElideRight, rect.width() )
         painter = QPainter ( self )
         
         painter.setPen( self.palette().color( QPalette.Disabled, QPalette.Text ) )
         painter.drawText( rect, va, text )
Exemple #13
0
    def paintEvent(self, event ):
        """QLineEdit.paintEvent implementation.
        Draws prompt
        """
        QLineEdit.paintEvent( self, event )

        if self._promptText and not self.text() and self.isEnabled() :
            option = QStyleOptionFrameV3()
            self.initStyleOption( option )

            left, top, right, bottom = self.getTextMargins()

            va = self.style().visualAlignment( self.layoutDirection(), self.alignment() )
            rect = self.style().subElementRect(
                QStyle.SE_LineEditContents, option, self ).adjusted( 2, 0, 0, 0 ).adjusted( left, top, -right, -bottom )
            fm = QFontMetrics ( self.font() )
            text = fm.elidedText( self._promptText, Qt.ElideRight, rect.width() )
            painter = QPainter ( self )

            painter.setPen( self.palette().color( QPalette.Disabled, QPalette.Text ) )
            painter.drawText( rect, va, text )
Exemple #14
0
def setElidedText(label, text):
    metrics = QFontMetrics(label.font())
    elidedText = metrics.elidedText(text, Qt.ElideRight, label.width())
    label.setText(elidedText)
Exemple #15
0
    def __paintEventNoStyle(self):
        p = QPainter(self)
        opt = QStyleOptionToolButton()
        self.initStyleOption(opt)

        fm = QFontMetrics(opt.font)
        palette = opt.palette

        # highlight brush is used as the background for the icon and background
        # when the tab is expanded and as mouse hover color (lighter).
        brush_highlight = palette.highlight()
        if opt.state & QStyle.State_Sunken:
            # State 'down' pressed during a mouse press (slightly darker).
            background_brush = brush_darker(brush_highlight, 110)
        elif opt.state & QStyle.State_MouseOver:
            background_brush = brush_darker(brush_highlight, 95)
        elif opt.state & QStyle.State_On:
            background_brush = brush_highlight
        else:
            # The default button brush.
            background_brush = palette.button()

        rect = opt.rect
        icon = opt.icon
        icon_size = opt.iconSize

        # TODO: add shift for pressed as set by the style (PM_ButtonShift...)

        pm = None
        if not icon.isNull():
            if opt.state & QStyle.State_Enabled:
                mode = QIcon.Normal
            else:
                mode = QIcon.Disabled

            pm = opt.icon.pixmap(
                rect.size().boundedTo(icon_size), mode,
                QIcon.On if opt.state & QStyle.State_On else QIcon.Off)

        icon_area_rect = QRect(rect)
        icon_area_rect.setRight(int(icon_area_rect.height() * 1.26))

        text_rect = QRect(rect)
        text_rect.setLeft(icon_area_rect.right() + 10)

        # Background  (TODO: Should the tab button have native
        # toolbutton shape, drawn using PE_PanelButtonTool or even
        # QToolBox tab shape)

        # Default outline pen
        pen = QPen(palette.color(QPalette.Mid))

        p.save()
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(background_brush))
        p.drawRect(rect)

        # Draw the background behind the icon if the background_brush
        # is different.
        if not opt.state & QStyle.State_On:
            p.setBrush(brush_highlight)
            p.drawRect(icon_area_rect)
            # Line between the icon and text
            p.setPen(pen)
            p.drawLine(icon_area_rect.topRight(), icon_area_rect.bottomRight())

        if opt.state & QStyle.State_HasFocus:
            # Set the focus frame pen and draw the border
            pen = QPen(QColor(FOCUS_OUTLINE_COLOR))
            p.setPen(pen)
            p.setBrush(Qt.NoBrush)
            # Adjust for pen
            rect = rect.adjusted(0, 0, -1, -1)
            p.drawRect(rect)

        else:
            p.setPen(pen)
            # Draw the top/bottom border
            if self.position == QStyleOptionToolBoxV2.OnlyOneTab or \
                    self.position == QStyleOptionToolBoxV2.Beginning or \
                    self.selected & \
                        QStyleOptionToolBoxV2.PreviousIsSelected:

                p.drawLine(rect.topLeft(), rect.topRight())

            p.drawLine(rect.bottomLeft(), rect.bottomRight())

        p.restore()

        p.save()
        text = fm.elidedText(opt.text, Qt.ElideRight, text_rect.width())
        p.setPen(QPen(palette.color(QPalette.ButtonText)))
        p.setFont(opt.font)

        p.drawText(text_rect,
                   int(Qt.AlignVCenter | Qt.AlignLeft) | \
                   int(Qt.TextSingleLine),
                   text)
        if pm:
            pm_rect = QRect(QPoint(0, 0), pm.size())
            centered_rect = QRect(pm_rect)
            centered_rect.moveCenter(icon_area_rect.center())
            p.drawPixmap(centered_rect, pm, pm_rect)
        p.restore()
class PackageDelegate(QStyledItemDelegate):

    AppStyle = qApp.style

    def __init__(self, parent=None, mainWindow=None, showDetailsButton=True, animatable=True):
        super(PackageDelegate, self).__init__(parent)
        self.webDialog = WebDialog(mainWindow)
        self.show_details_button = showDetailsButton

        self.rowAnimator = RowAnimator(parent.packageList)
        self.defaultIcon = KIcon(('package-x-generic', 'package_applications'), 32)
        self.defaultInstalledIcon = QIcon(KIconLoader.loadOverlayed(('package-x-generic', 'package_applications'), CHECK_ICON, 32))
        self.animatable = animatable
        self._max_height = ROW_HEIGHT

        self._rt_0 = QIcon(":/data/star_0.png")
        self._rt_1 = QIcon(":/data/star_1.png")

        self.types = {'critical':(RED,     i18n('critical')),
                      'security':(DARKRED, i18n('security'))}

        self.font = Pds.settings('font','Sans,10').split(',')[0]

        self.normalFont = QFont(self.font, 10, QFont.Normal)
        self.boldFont = QFont(self.font, 11, QFont.Bold)
        self.normalDetailFont = QFont(self.font, 9, QFont.Normal)
        self.boldDetailFont = QFont(self.font, 9, QFont.Bold)
        self.tagFont = QFont(self.font, 7, QFont.Normal)

        self.tagFontFM = QFontMetrics(self.tagFont)
        self.boldFontFM = QFontMetrics(self.boldFont)
        self.boldDetailFontFM = QFontMetrics(self.boldDetailFont)
        self.normalFontFM = QFontMetrics(self.normalFont)
        self.normalDetailFontFM = QFontMetrics(self.normalDetailFont)

        self._titles = {'description': i18n("Description:"),
                        'website'    : i18n("Website:"),
                        'release'    : i18n("Release:"),
                        'repository' : i18n("Repository:"),
                        'size'       : i18n("Package Size:"),
                        'installVers': i18n("Installed Version:")}

        self._titleFM = {}
        for key, value in self._titles.items():
            self._titleFM[key] = self.boldDetailFontFM.width(value) + ICON_SIZE + 3

        self.baseWidth = self.boldFontFM.width(max(self._titles.values(), key=len)) + ICON_SIZE
        self.parent = parent.packageList

        # Base style for some of important features
        # self.plastik = QStyleFactory.create('plastique')

    def paint(self, painter, option, index):
        if not index.isValid():
            return super(PackageDelegate, self).paint(painter, option, index)

        if index.flags() & Qt.ItemIsUserCheckable:
            if index.column() == 0:
                self.paintCheckBoxColumn(painter, option, index)
            else:
                self.paintInfoColumn(painter, option, index)
        else:
            self.paintInfoColumn(painter, option, index, width_limit = 10)

    def paintCheckBoxColumn(self, painter, option, index):
        opt = QStyleOptionViewItemV4(option)

        buttonStyle = QStyleOptionButton()
        buttonStyle.state = QStyle.State_On if index.model().data(index, Qt.CheckStateRole) == QVariant(Qt.Checked) else QStyle.State_Off

        if option.state & QStyle.State_MouseOver or option.state & QStyle.State_HasFocus:
            buttonStyle.state |= QStyle.State_HasFocus

        buttonStyle.rect = opt.rect.adjusted(4, -opt.rect.height() + ROW_HEIGHT, 0, 0)
        PackageDelegate.AppStyle().drawControl(QStyle.CE_CheckBox, buttonStyle, painter, None)

    def paintInfoColumn(self, painter, option, index, width_limit = 0):
        left = option.rect.left() + 3
        top = option.rect.top()
        width = option.rect.width() - width_limit

        pixmap = QPixmap(option.rect.size())
        pixmap.fill(Qt.transparent)

        p = QPainter(pixmap)
        p.setRenderHint(QPainter.Antialiasing, True)
        p.translate(-option.rect.topLeft())

        textInner = 2 * ICON_PADDING + ROW_HEIGHT - 10
        itemHeight = ROW_HEIGHT + 2 * ICON_PADDING

        margin = left + ICON_PADDING - 10

        title = index.model().data(index, NameRole).toString()
        summary = index.model().data(index, SummaryRole).toString()
        ptype = str(index.model().data(index, TypeRole).toString())
        rate = int(index.model().data(index, RateRole).toInt()[0])
        installed = index.model().data(index, InstalledRole).toBool()

        # We need to request update if its not possible to get meta data about the package
        try:
            # Get Package Icon if exists
            _icon = index.model().data(index, Qt.DecorationRole).toString()
        except:
            p.end()
            painter.drawPixmap(option.rect.topLeft(), pixmap)
            self.parent.requestUpdate()
            return

        icon = None

        if _icon:
            overlay = [CHECK_ICON] if installed else []
            KIconLoader._forceCache = True
            pix = KIconLoader.loadOverlayed(_icon, overlay, 32)
            if not pix.isNull():
                icon = QIcon(pix.scaled(QSize(32, 32), Qt.KeepAspectRatio, Qt.SmoothTransformation))
            KIconLoader._forceCache = False

        if not icon:
            icon = self.defaultIcon if not installed else self.defaultInstalledIcon

        # Paint the Icon
        icon.paint(p, margin, top + ICON_PADDING, ROW_HEIGHT, ROW_HEIGHT, Qt.AlignCenter)

        fix_pos = 0
        if index.model().columnCount() <= 1:
            fix_pos = 22

        if config.USE_APPINFO:
            # Rating Stars
            for _rt_i in range(5):
                self._rt_0.paint(p, width + 10 * _rt_i - 30 - fix_pos, top + ROW_HEIGHT / 4, 10, 10, Qt.AlignCenter)
            for _rt_i in range(rate):
                self._rt_1.paint(p, width + 10 * _rt_i - 30 - fix_pos, top + ROW_HEIGHT / 4, 10, 10, Qt.AlignCenter)

        foregroundColor = option.palette.color(QPalette.Text)
        p.setPen(foregroundColor)

        # Package Name
        p.setFont(self.boldFont)
        p.drawText(left + textInner, top, width - textInner, itemHeight / 2, Qt.AlignBottom | Qt.AlignLeft, title)

        tagWidth = 0

        _component_width = 0
        if self.parent.showComponents:
            component = str(index.model().data(index, ComponentRole).toString())
            widthOfTitle = self.boldFontFM.width(title) + 6 + left + textInner

            p.setFont(self.tagFont)
            rect = self.tagFontFM.boundingRect(option.rect, Qt.TextWordWrap, component)
            p.setPen(LIGHTGREEN)
            p.setBrush(LIGHTGREEN)
            p.drawRoundRect(widthOfTitle , top + 12, rect.width() + 4, rect.height(), 10, 10)
            p.setPen(DARKGREEN)
            p.drawText(widthOfTitle + 2, top + 12, rect.width(), rect.height(), Qt.AlignCenter, component)
            p.setPen(foregroundColor)
            _component_width = rect.width() + 8

        if self.parent.showIsA:
            isa = str(index.model().data(index, IsaRole).toString())
            if not isa == '':
                widthOfTitle = self.boldFontFM.width(title) + 6 + left + textInner + _component_width

                p.setFont(self.tagFont)
                rect = self.tagFontFM.boundingRect(option.rect, Qt.TextWordWrap, isa)
                p.setPen(LIGHTBLUE)
                p.setBrush(LIGHTBLUE)
                p.drawRoundRect(widthOfTitle , top + 12, rect.width() + 4, rect.height(), 10, 10)
                p.setPen(DARKVIOLET)
                p.drawText(widthOfTitle + 2, top + 12, rect.width(), rect.height(), Qt.AlignCenter, isa)
                p.setPen(foregroundColor)
                _component_width += rect.width() + 8

        if ptype not in ('None', 'normal'):
            widthOfTitle = self.boldFontFM.width(title) + 6 + left + textInner + _component_width
            p.setFont(self.tagFont)
            rect = self.tagFontFM.boundingRect(option.rect, Qt.TextWordWrap, self.types[ptype][1])
            p.setPen(self.types[ptype][0])
            p.setBrush(self.types[ptype][0])
            p.drawRoundRect(widthOfTitle, top + 12, rect.width() + 4, rect.height(), 10, 10)
            p.setPen(WHITE)
            p.drawText(widthOfTitle + 2, top + 12, rect.width(), rect.height(), Qt.AlignCenter, self.types[ptype][1])
            p.setPen(foregroundColor)
            tagWidth = rect.width()

        # Package Summary
        p.setFont(self.normalFont)
        foregroundColor.setAlpha(160)
        p.setPen(foregroundColor)
        elided_summary = self.normalFontFM.elidedText(summary, Qt.ElideRight, width - textInner - tagWidth - 22)
        p.drawText(left + textInner, top + itemHeight / 2, width - textInner, itemHeight / 2, Qt.TextDontClip, elided_summary)
        foregroundColor.setAlpha(255)
        p.setPen(foregroundColor)

        buttonStyle = None
        if self.rowAnimator.currentRow() == index.row():
            description = index.model().data(index, DescriptionRole).toString()
            size = index.model().data(index, SizeRole).toString()
            homepage = index.model().data(index, HomepageRole).toString()
            installedVersion = str(index.model().data(index, InstalledVersionRole).toString())
            version = index.model().data(index, VersionRole)

            # Package Detail Label
            position = top + ROW_HEIGHT

            p.setFont(self.normalDetailFont)
            baseRect = QRect(left, position, width - 8, option.rect.height())
            rect = self.normalDetailFontFM.boundingRect(baseRect, Qt.TextWordWrap | Qt.TextDontClip, description)
            p.drawText(left + 2, position, width - 8, rect.height(), Qt.TextWordWrap | Qt.TextDontClip, description)

            # Package Detail Homepage
            position += rect.height() + 4

            p.setFont(self.boldDetailFont)
            p.drawText(left + ICON_SIZE , position, width - textInner, itemHeight / 2, Qt.AlignLeft, self._titles['website'])

            p.setFont(self.normalDetailFont)
            homepage = self.normalDetailFontFM.elidedText(homepage, Qt.ElideRight, width - self._titleFM['website'])
            rect = self.normalDetailFontFM.boundingRect(option.rect, Qt.TextSingleLine, homepage)
            self.rowAnimator.hoverLinkFilter.link_rect = QRect(left + self._titleFM['website'] + 2, position + 2 + 32, rect.width(), rect.height())

            p.setPen(option.palette.color(QPalette.Link))
            p.drawText(left + self._titleFM['website'], position, width, rect.height(), Qt.TextSingleLine, homepage)
            p.setPen(foregroundColor)

            # Package Detail Version
            position += rect.height()

            p.setFont(self.boldDetailFont)
            p.drawText(left + ICON_SIZE , position, width - textInner, itemHeight / 2, Qt.AlignLeft, self._titles['release'])

            p.setFont(self.normalDetailFont)
            rect = self.normalDetailFontFM.boundingRect(option.rect, Qt.TextWordWrap, version.toString())
            p.drawText(left + self._titleFM['release'], position, width, rect.height(), Qt.TextWordWrap, version.toString())

            if not installedVersion == '':
                position += rect.height()

                p.setFont(self.boldDetailFont)
                p.drawText(left + ICON_SIZE , position, width - textInner, itemHeight / 2, Qt.AlignLeft, self._titles['installVers'])

                p.setFont(self.normalDetailFont)
                rect = self.normalDetailFontFM.boundingRect(option.rect, Qt.TextWordWrap, installedVersion)
                p.drawText(left + self._titleFM['installVers'], position, width, rect.height(), Qt.TextWordWrap, installedVersion)

            # Package Detail Repository
            repository = index.model().data(index, RepositoryRole).toString()
            if not repository == '':
                repository = i18n('Unknown')  if repository == 'N/A' else repository
                position += rect.height()

                p.setFont(self.boldDetailFont)
                p.drawText(left + ICON_SIZE , position, width - textInner, itemHeight / 2, Qt.AlignLeft, self._titles['repository'])

                p.setFont(self.normalDetailFont)
                p.drawText(left + self._titleFM['repository'], position, width, itemHeight / 2, Qt.TextWordWrap, repository)

            # Package Detail Size
            position += rect.height()

            p.setFont(self.boldDetailFont)
            p.drawText(left + ICON_SIZE , position, width - textInner, itemHeight / 2, Qt.AlignLeft, self._titles['size'])

            p.setFont(self.normalDetailFont)
            p.drawText(left + self._titleFM['size'], position, width, itemHeight / 2, Qt.TextWordWrap, size)
            position += rect.height()
            self.rowAnimator.max_height = position - top + 8

            # Package More info button
            opt = QStyleOptionViewItemV4(option)

            buttonStyle = QStyleOptionButton()
            if option.state & QStyle.State_MouseOver or option.state & QStyle.State_HasFocus:
                buttonStyle.state |= QStyle.State_HasFocus
            buttonStyle.state |= QStyle.State_Enabled
            buttonStyle.text = i18n("Details")

            buttonStyle.rect = QRect(width - 100, position - 22, 100, 22)

        p.end()

        # FIXME
        # if option.state & QStyle.State_HasFocus and self.animatable:
        #     option.state |= QStyle.State_MouseOver
            # Use Plastique style to draw focus rect like MouseOver effect of Oxygen.
            # self.plastik.drawPrimitive(QStyle.PE_FrameLineEdit, option, painter, None)

        if not self.rowAnimator.running() and buttonStyle:
            if self.show_details_button and (installed or config.USE_APPINFO):
                PackageDelegate.AppStyle().drawControl(QStyle.CE_PushButton, buttonStyle, painter, None)
                self.rowAnimator.hoverLinkFilter.button_rect = QRect(buttonStyle.rect)

        painter.drawPixmap(option.rect.topLeft(), pixmap)
        del pixmap

    def editorEvent(self, event, model, option, index):
        if event.type() == QEvent.MouseButtonRelease and index.column() == 0 and index.flags() & Qt.ItemIsUserCheckable:
            toggled = Qt.Checked if model.data(index, Qt.CheckStateRole) == QVariant(Qt.Unchecked) else Qt.Unchecked
            return model.setData(index, toggled, Qt.CheckStateRole)
        __event = QItemDelegate(self).editorEvent(event, model, option, index)
        animate_requested = False
        if event.type() == QEvent.MouseButtonRelease and self.animatable:
            if self.rowAnimator.row == index.row():
                epos = event.pos()
                if self.rowAnimator.hoverLinkFilter.link_rect.contains(QPoint(epos.x(), epos.y() + 32)):
                    url = QUrl(model.data(index, HomepageRole).toString())
                    QDesktopServices.openUrl(url)
                    return __event
                elif self.rowAnimator.hoverLinkFilter.button_rect.contains(epos, True):
                    self.showPackageDetails(model, index)
                    return __event
            animate_requested = True
        elif event.type() == QEvent.KeyPress and self.animatable:
            # KeyCode 32 : Space key
            if event.key() == 32 and index.column() == index.model().columnCount() - 1:
                animate_requested = True
        if not unicode(model.data(index, DescriptionRole).toString()) == '' and animate_requested:
            self.rowAnimator.animate(index.row())
        return __event

    def showPackageDetails(self, model, index):

        def _getter(role):
            return model.data(index, role).toString()

        name = _getter(NameRole)
        summary = _getter(SummaryRole)
        description = _getter(DescriptionRole)
        installed = model.data(index, InstalledRole).toBool()
        self.webDialog.showPackageDetails(name, installed, summary, description)

    def sizeHint(self, option, index):
        if self.rowAnimator.currentRow() == index.row() and not index.row() == 0:
            return self.rowAnimator.size()
        else:
            width = ICON_SIZE if index.column() == 0 else 0
            return QSize(width, ROW_HEIGHT)

    def setAnimatable(self, animatable):
        self.animatable = animatable

    def reset(self):
        self.rowAnimator.reset()
Exemple #17
0
class PackageDelegate(QStyledItemDelegate):

    AppStyle = qApp.style

    def __init__(self,
                 parent=None,
                 mainWindow=None,
                 showDetailsButton=True,
                 animatable=True):
        super(PackageDelegate, self).__init__(parent)
        self.webDialog = WebDialog(mainWindow)
        self.show_details_button = showDetailsButton

        self.rowAnimator = RowAnimator(parent.packageList)
        self.defaultIcon = KIcon(('package-x-generic', 'package_applications'),
                                 32)
        self.defaultInstalledIcon = QIcon(
            KIconLoader.loadOverlayed(
                ('package-x-generic', 'package_applications'), CHECK_ICON, 32))
        self.animatable = animatable
        self._max_height = ROW_HEIGHT

        self._rt_0 = QIcon(":/data/star_0.png")
        self._rt_1 = QIcon(":/data/star_1.png")

        self.types = {
            'critical': (RED, i18n('critical')),
            'security': (DARKRED, i18n('security'))
        }

        self.font = Pds.settings('font', 'Sans,10').split(',')[0]

        self.normalFont = QFont(self.font, 10, QFont.Normal)
        self.boldFont = QFont(self.font, 11, QFont.Bold)
        self.normalDetailFont = QFont(self.font, 9, QFont.Normal)
        self.boldDetailFont = QFont(self.font, 9, QFont.Bold)
        self.tagFont = QFont(self.font, 7, QFont.Normal)

        self.tagFontFM = QFontMetrics(self.tagFont)
        self.boldFontFM = QFontMetrics(self.boldFont)
        self.boldDetailFontFM = QFontMetrics(self.boldDetailFont)
        self.normalFontFM = QFontMetrics(self.normalFont)
        self.normalDetailFontFM = QFontMetrics(self.normalDetailFont)

        self._titles = {
            'description': i18n("Description:"),
            'website': i18n("Website:"),
            'release': i18n("Release:"),
            'repository': i18n("Repository:"),
            'size': i18n("Package Size:"),
            'installVers': i18n("Installed Version:")
        }

        self._titleFM = {}
        for key, value in self._titles.items():
            self._titleFM[key] = self.boldDetailFontFM.width(
                value) + ICON_SIZE + 3

        self.baseWidth = self.boldFontFM.width(
            max(self._titles.values(), key=len)) + ICON_SIZE
        self.parent = parent.packageList

        # Base style for some of important features
        # self.plastik = QStyleFactory.create('plastique')

    def paint(self, painter, option, index):
        if not index.isValid():
            return super(PackageDelegate, self).paint(painter, option, index)

        if index.flags() & Qt.ItemIsUserCheckable:
            if index.column() == 0:
                self.paintCheckBoxColumn(painter, option, index)
            else:
                self.paintInfoColumn(painter, option, index)
        else:
            self.paintInfoColumn(painter, option, index, width_limit=10)

    def paintCheckBoxColumn(self, painter, option, index):
        opt = QStyleOptionViewItemV4(option)

        buttonStyle = QStyleOptionButton()
        buttonStyle.state = QStyle.State_On if index.model().data(
            index, Qt.CheckStateRole) == QVariant(
                Qt.Checked) else QStyle.State_Off

        if option.state & QStyle.State_MouseOver or option.state & QStyle.State_HasFocus:
            buttonStyle.state |= QStyle.State_HasFocus

        buttonStyle.rect = opt.rect.adjusted(4,
                                             -opt.rect.height() + ROW_HEIGHT,
                                             0, 0)
        PackageDelegate.AppStyle().drawControl(QStyle.CE_CheckBox, buttonStyle,
                                               painter, None)

    def paintInfoColumn(self, painter, option, index, width_limit=0):
        left = option.rect.left() + 3
        top = option.rect.top()
        width = option.rect.width() - width_limit

        pixmap = QPixmap(option.rect.size())
        pixmap.fill(Qt.transparent)

        p = QPainter(pixmap)
        p.setRenderHint(QPainter.Antialiasing, True)
        p.translate(-option.rect.topLeft())

        textInner = 2 * ICON_PADDING + ROW_HEIGHT - 10
        itemHeight = ROW_HEIGHT + 2 * ICON_PADDING

        margin = left + ICON_PADDING - 10

        title = index.model().data(index, NameRole).toString()
        summary = index.model().data(index, SummaryRole).toString()
        ptype = str(index.model().data(index, TypeRole).toString())
        rate = int(index.model().data(index, RateRole).toInt()[0])
        installed = index.model().data(index, InstalledRole).toBool()

        # We need to request update if its not possible to get meta data about the package
        try:
            # Get Package Icon if exists
            _icon = index.model().data(index, Qt.DecorationRole).toString()
        except:
            p.end()
            painter.drawPixmap(option.rect.topLeft(), pixmap)
            self.parent.requestUpdate()
            return

        icon = None

        if _icon:
            overlay = [CHECK_ICON] if installed else []
            KIconLoader._forceCache = True
            pix = KIconLoader.loadOverlayed(_icon, overlay, 32)
            if not pix.isNull():
                icon = QIcon(
                    pix.scaled(QSize(32, 32), Qt.KeepAspectRatio,
                               Qt.SmoothTransformation))
            KIconLoader._forceCache = False

        if not icon:
            icon = self.defaultIcon if not installed else self.defaultInstalledIcon

        # Paint the Icon
        icon.paint(p, margin, top + ICON_PADDING, ROW_HEIGHT, ROW_HEIGHT,
                   Qt.AlignCenter)

        fix_pos = 0
        if index.model().columnCount() <= 1:
            fix_pos = 22

        if config.USE_APPINFO:
            # Rating Stars
            for _rt_i in range(5):
                self._rt_0.paint(p, width + 10 * _rt_i - 30 - fix_pos,
                                 top + ROW_HEIGHT / 4, 10, 10, Qt.AlignCenter)
            for _rt_i in range(rate):
                self._rt_1.paint(p, width + 10 * _rt_i - 30 - fix_pos,
                                 top + ROW_HEIGHT / 4, 10, 10, Qt.AlignCenter)

        foregroundColor = option.palette.color(QPalette.Text)
        p.setPen(foregroundColor)

        # Package Name
        p.setFont(self.boldFont)
        p.drawText(left + textInner, top, width - textInner, itemHeight / 2,
                   Qt.AlignBottom | Qt.AlignLeft, title)

        tagWidth = 0

        _component_width = 0
        if self.parent.showComponents:
            component = str(index.model().data(index,
                                               ComponentRole).toString())
            widthOfTitle = self.boldFontFM.width(title) + 6 + left + textInner

            p.setFont(self.tagFont)
            rect = self.tagFontFM.boundingRect(option.rect, Qt.TextWordWrap,
                                               component)
            p.setPen(LIGHTGREEN)
            p.setBrush(LIGHTGREEN)
            p.drawRoundRect(widthOfTitle, top + 12,
                            rect.width() + 4, rect.height(), 10, 10)
            p.setPen(DARKGREEN)
            p.drawText(widthOfTitle + 2, top + 12, rect.width(), rect.height(),
                       Qt.AlignCenter, component)
            p.setPen(foregroundColor)
            _component_width = rect.width() + 8

        if self.parent.showIsA:
            isa = str(index.model().data(index, IsaRole).toString())
            if not isa == '':
                widthOfTitle = self.boldFontFM.width(
                    title) + 6 + left + textInner + _component_width

                p.setFont(self.tagFont)
                rect = self.tagFontFM.boundingRect(option.rect,
                                                   Qt.TextWordWrap, isa)
                p.setPen(LIGHTBLUE)
                p.setBrush(LIGHTBLUE)
                p.drawRoundRect(widthOfTitle, top + 12,
                                rect.width() + 4, rect.height(), 10, 10)
                p.setPen(DARKVIOLET)
                p.drawText(widthOfTitle + 2, top + 12, rect.width(),
                           rect.height(), Qt.AlignCenter, isa)
                p.setPen(foregroundColor)
                _component_width += rect.width() + 8

        if ptype not in ('None', 'normal'):
            widthOfTitle = self.boldFontFM.width(
                title) + 6 + left + textInner + _component_width
            p.setFont(self.tagFont)
            rect = self.tagFontFM.boundingRect(option.rect, Qt.TextWordWrap,
                                               self.types[ptype][1])
            p.setPen(self.types[ptype][0])
            p.setBrush(self.types[ptype][0])
            p.drawRoundRect(widthOfTitle, top + 12,
                            rect.width() + 4, rect.height(), 10, 10)
            p.setPen(WHITE)
            p.drawText(widthOfTitle + 2, top + 12, rect.width(), rect.height(),
                       Qt.AlignCenter, self.types[ptype][1])
            p.setPen(foregroundColor)
            tagWidth = rect.width()

        # Package Summary
        p.setFont(self.normalFont)
        foregroundColor.setAlpha(160)
        p.setPen(foregroundColor)
        elided_summary = self.normalFontFM.elidedText(
            summary, Qt.ElideRight, width - textInner - tagWidth - 22)
        p.drawText(left + textInner, top + itemHeight / 2, width - textInner,
                   itemHeight / 2, Qt.TextDontClip, elided_summary)
        foregroundColor.setAlpha(255)
        p.setPen(foregroundColor)

        buttonStyle = None
        if self.rowAnimator.currentRow() == index.row():
            description = index.model().data(index, DescriptionRole).toString()
            size = index.model().data(index, SizeRole).toString()
            homepage = index.model().data(index, HomepageRole).toString()
            installedVersion = str(index.model().data(
                index, InstalledVersionRole).toString())
            version = index.model().data(index, VersionRole)

            # Package Detail Label
            position = top + ROW_HEIGHT

            p.setFont(self.normalDetailFont)
            baseRect = QRect(left, position, width - 8, option.rect.height())
            rect = self.normalDetailFontFM.boundingRect(
                baseRect, Qt.TextWordWrap | Qt.TextDontClip, description)
            p.drawText(left + 2, position, width - 8, rect.height(),
                       Qt.TextWordWrap | Qt.TextDontClip, description)

            # Package Detail Homepage
            position += rect.height() + 4

            p.setFont(self.boldDetailFont)
            p.drawText(left + ICON_SIZE, position, width - textInner,
                       itemHeight / 2, Qt.AlignLeft, self._titles['website'])

            p.setFont(self.normalDetailFont)
            homepage = self.normalDetailFontFM.elidedText(
                homepage, Qt.ElideRight, width - self._titleFM['website'])
            rect = self.normalDetailFontFM.boundingRect(
                option.rect, Qt.TextSingleLine, homepage)
            self.rowAnimator.hoverLinkFilter.link_rect = QRect(
                left + self._titleFM['website'] + 2, position + 2 + 32,
                rect.width(), rect.height())

            p.setPen(option.palette.color(QPalette.Link))
            p.drawText(left + self._titleFM['website'], position, width,
                       rect.height(), Qt.TextSingleLine, homepage)
            p.setPen(foregroundColor)

            # Package Detail Version
            position += rect.height()

            p.setFont(self.boldDetailFont)
            p.drawText(left + ICON_SIZE, position, width - textInner,
                       itemHeight / 2, Qt.AlignLeft, self._titles['release'])

            p.setFont(self.normalDetailFont)
            rect = self.normalDetailFontFM.boundingRect(
                option.rect, Qt.TextWordWrap, version.toString())
            p.drawText(left + self._titleFM['release'], position, width,
                       rect.height(), Qt.TextWordWrap, version.toString())

            if not installedVersion == '':
                position += rect.height()

                p.setFont(self.boldDetailFont)
                p.drawText(left + ICON_SIZE, position, width - textInner,
                           itemHeight / 2, Qt.AlignLeft,
                           self._titles['installVers'])

                p.setFont(self.normalDetailFont)
                rect = self.normalDetailFontFM.boundingRect(
                    option.rect, Qt.TextWordWrap, installedVersion)
                p.drawText(left + self._titleFM['installVers'], position,
                           width, rect.height(), Qt.TextWordWrap,
                           installedVersion)

            # Package Detail Repository
            repository = index.model().data(index, RepositoryRole).toString()
            if not repository == '':
                repository = i18n(
                    'Unknown') if repository == 'N/A' else repository
                position += rect.height()

                p.setFont(self.boldDetailFont)
                p.drawText(left + ICON_SIZE, position, width - textInner,
                           itemHeight / 2, Qt.AlignLeft,
                           self._titles['repository'])

                p.setFont(self.normalDetailFont)
                p.drawText(left + self._titleFM['repository'], position, width,
                           itemHeight / 2, Qt.TextWordWrap, repository)

            # Package Detail Size
            position += rect.height()

            p.setFont(self.boldDetailFont)
            p.drawText(left + ICON_SIZE, position, width - textInner,
                       itemHeight / 2, Qt.AlignLeft, self._titles['size'])

            p.setFont(self.normalDetailFont)
            p.drawText(left + self._titleFM['size'], position, width,
                       itemHeight / 2, Qt.TextWordWrap, size)
            position += rect.height()
            self.rowAnimator.max_height = position - top + 8

            # Package More info button
            opt = QStyleOptionViewItemV4(option)

            buttonStyle = QStyleOptionButton()
            if option.state & QStyle.State_MouseOver or option.state & QStyle.State_HasFocus:
                buttonStyle.state |= QStyle.State_HasFocus
            buttonStyle.state |= QStyle.State_Enabled
            buttonStyle.text = i18n("Details")

            buttonStyle.rect = QRect(width - 100, position - 22, 100, 22)

        p.end()

        # FIXME
        # if option.state & QStyle.State_HasFocus and self.animatable:
        #     option.state |= QStyle.State_MouseOver
        # Use Plastique style to draw focus rect like MouseOver effect of Oxygen.
        # self.plastik.drawPrimitive(QStyle.PE_FrameLineEdit, option, painter, None)

        if not self.rowAnimator.running() and buttonStyle:
            if self.show_details_button and (installed or config.USE_APPINFO):
                PackageDelegate.AppStyle().drawControl(QStyle.CE_PushButton,
                                                       buttonStyle, painter,
                                                       None)
                self.rowAnimator.hoverLinkFilter.button_rect = QRect(
                    buttonStyle.rect)

        painter.drawPixmap(option.rect.topLeft(), pixmap)
        del pixmap

    def editorEvent(self, event, model, option, index):
        if event.type() == QEvent.MouseButtonRelease and index.column(
        ) == 0 and index.flags() & Qt.ItemIsUserCheckable:
            toggled = Qt.Checked if model.data(
                index, Qt.CheckStateRole) == QVariant(
                    Qt.Unchecked) else Qt.Unchecked
            return model.setData(index, toggled, Qt.CheckStateRole)
        __event = QItemDelegate(self).editorEvent(event, model, option, index)
        animate_requested = False
        if event.type() == QEvent.MouseButtonRelease and self.animatable:
            if self.rowAnimator.row == index.row():
                epos = event.pos()
                if self.rowAnimator.hoverLinkFilter.link_rect.contains(
                        QPoint(epos.x(),
                               epos.y() + 32)):
                    url = QUrl(model.data(index, HomepageRole).toString())
                    QDesktopServices.openUrl(url)
                    return __event
                elif self.rowAnimator.hoverLinkFilter.button_rect.contains(
                        epos, True):
                    self.showPackageDetails(model, index)
                    return __event
            animate_requested = True
        elif event.type() == QEvent.KeyPress and self.animatable:
            # KeyCode 32 : Space key
            if event.key() == 32 and index.column(
            ) == index.model().columnCount() - 1:
                animate_requested = True
        if not unicode(model.data(
                index,
                DescriptionRole).toString()) == '' and animate_requested:
            self.rowAnimator.animate(index.row())
        return __event

    def showPackageDetails(self, model, index):
        def _getter(role):
            return model.data(index, role).toString()

        name = _getter(NameRole)
        summary = _getter(SummaryRole)
        description = _getter(DescriptionRole)
        installed = model.data(index, InstalledRole).toBool()
        self.webDialog.showPackageDetails(name, installed, summary,
                                          description)

    def sizeHint(self, option, index):
        if self.rowAnimator.currentRow() == index.row(
        ) and not index.row() == 0:
            return self.rowAnimator.size()
        else:
            width = ICON_SIZE if index.column() == 0 else 0
            return QSize(width, ROW_HEIGHT)

    def setAnimatable(self, animatable):
        self.animatable = animatable

    def reset(self):
        self.rowAnimator.reset()
Exemple #18
0
    def __paintEventNoStyle(self):
        p = QPainter(self)
        opt = QStyleOptionToolButton()
        self.initStyleOption(opt)

        fm = QFontMetrics(opt.font)
        palette = opt.palette

        # highlight brush is used as the background for the icon and background
        # when the tab is expanded and as mouse hover color (lighter).
        brush_highlight = palette.highlight()
        if opt.state & QStyle.State_Sunken:
            # State 'down' pressed during a mouse press (slightly darker).
            background_brush = brush_darker(brush_highlight, 110)
        elif opt.state & QStyle.State_MouseOver:
            background_brush = brush_darker(brush_highlight, 95)
        elif opt.state & QStyle.State_On:
            background_brush = brush_highlight
        else:
            # The default button brush.
            background_brush = palette.button()

        rect = opt.rect
        icon = opt.icon
        icon_size = opt.iconSize

        # TODO: add shift for pressed as set by the style (PM_ButtonShift...)

        pm = None
        if not icon.isNull():
            if opt.state & QStyle.State_Enabled:
                mode = QIcon.Normal
            else:
                mode = QIcon.Disabled

            pm = opt.icon.pixmap(
                    rect.size().boundedTo(icon_size), mode,
                    QIcon.On if opt.state & QStyle.State_On else QIcon.Off)

        icon_area_rect = QRect(rect)
        icon_area_rect.setRight(int(icon_area_rect.height() * 1.26))

        text_rect = QRect(rect)
        text_rect.setLeft(icon_area_rect.right() + 10)

        # Background  (TODO: Should the tab button have native
        # toolbutton shape, drawn using PE_PanelButtonTool or even
        # QToolBox tab shape)

        # Default outline pen
        pen = QPen(palette.color(QPalette.Mid))

        p.save()
        p.setPen(Qt.NoPen)
        p.setBrush(QBrush(background_brush))
        p.drawRect(rect)

        # Draw the background behind the icon if the background_brush
        # is different.
        if not opt.state & QStyle.State_On:
            p.setBrush(brush_highlight)
            p.drawRect(icon_area_rect)
            # Line between the icon and text
            p.setPen(pen)
            p.drawLine(icon_area_rect.topRight(),
                       icon_area_rect.bottomRight())

        if opt.state & QStyle.State_HasFocus:
            # Set the focus frame pen and draw the border
            pen = QPen(QColor(FOCUS_OUTLINE_COLOR))
            p.setPen(pen)
            p.setBrush(Qt.NoBrush)
            # Adjust for pen
            rect = rect.adjusted(0, 0, -1, -1)
            p.drawRect(rect)

        else:
            p.setPen(pen)
            # Draw the top/bottom border
            if self.position == QStyleOptionToolBoxV2.OnlyOneTab or \
                    self.position == QStyleOptionToolBoxV2.Beginning or \
                    self.selected & \
                        QStyleOptionToolBoxV2.PreviousIsSelected:

                p.drawLine(rect.topLeft(), rect.topRight())

            p.drawLine(rect.bottomLeft(), rect.bottomRight())

        p.restore()

        p.save()
        text = fm.elidedText(opt.text, Qt.ElideRight, text_rect.width())
        p.setPen(QPen(palette.color(QPalette.ButtonText)))
        p.setFont(opt.font)

        p.drawText(text_rect,
                   int(Qt.AlignVCenter | Qt.AlignLeft) | \
                   int(Qt.TextSingleLine),
                   text)
        if pm:
            pm_rect = QRect(QPoint(0, 0), pm.size())
            centered_rect = QRect(pm_rect)
            centered_rect.moveCenter(icon_area_rect.center())
            p.drawPixmap(centered_rect, pm, pm_rect)
        p.restore()
    def paint (self, painter, option, index):
        '''
        QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index
        '''

        orntnDelegate = self.chooseOrientationDelegate()
        
        painter.save()

        if option.state & QStyle.State_Selected:
            borderPen = QPen(Qt.blue)
            borderPen.setWidth(3)
            nameBgColors = [Qt.white, Qt.yellow]
        else:
            borderPen = QPen(Qt.lightGray)
            lightBlue = QColor(0, 0, 255).lighter(180)
            nameBgColors = [Qt.white, lightBlue]

        # Set default font and color
        itemRect = option.rect
        painter.fillRect(itemRect, Qt.white)
        painter.setFont(orntnDelegate.getNameFont())
        painter.setPen(Qt.black)

        m = index.model()

        ticker = m.data(index, PositionsModel.ROLE_TICKER)
        companyName = m.data(index, Qt.DisplayRole)
        line2 = m.data(index, PositionsModel.ROLE_CURRENT_PRICE)
        line3 = m.data(index, PositionsModel.ROLE_CHANGE)

        fontMetricsCompanyName = QFontMetrics(orntnDelegate.getNameFont())
        fontMetricsTicker = QFontMetrics(orntnDelegate.getTickerFont())
        fontMetricsCurrentPrice = QFontMetrics(orntnDelegate.getCurrentPriceFont())
        fontMetricsChange = QFontMetrics(orntnDelegate.getChangeFont())
        lineSp1 = fontMetricsCompanyName.lineSpacing()
        lineSp2 = fontMetricsCurrentPrice.lineSpacing()
        lineSp3 = fontMetricsChange.lineSpacing()

        # Company Name    (EXCHANGE:SYMBOL)
        textRectShade = QRect(itemRect.left(),
                              itemRect.top(),
                              itemRect.width(),
                              self.MARGIN + lineSp1 + self.MARGIN)
        gradient = self.createLinearGradient(textRectShade,
                                             nameBgColors[0],
                                             nameBgColors[1])
        painter.fillRect(textRectShade, gradient)
        textRect = QRect(itemRect.left() + self.MARGIN, itemRect.top() + self.MARGIN,
                         itemRect.width() - 2 * self.MARGIN, lineSp1 + self.MARGIN)
        painter.setFont(orntnDelegate.getNameFont())
        # Shorten the company name such that long company names are not written on top of the ticker
        tickerTextW = fontMetricsTicker.width(ticker)
        companyNameTextW = textRect.width() - tickerTextW - 2 * self.MARGIN
        companyName = fontMetricsCompanyName.elidedText(companyName, Qt.ElideRight, companyNameTextW)
        painter.drawText(textRect, Qt.AlignVCenter | Qt.AlignLeft, companyName)
        painter.setFont(orntnDelegate.getTickerFont())
        painter.drawText(textRect, Qt.AlignVCenter | Qt.AlignRight, "(%s)" % (ticker))

        # Current price
        painter.setFont(orntnDelegate.getCurrentPriceFont())
        textRect.adjust(0, lineSp1 + self.MARGIN, 0, lineSp2 + self.MARGIN)
        painter.drawText(textRect, Qt.AlignTop | Qt.AlignLeft, line2)

        rightColRect = QRect(textRect.left(), textRect.top(),
                             textRect.width(), textRect.height())

        # Change
        ccol = m.data(index, PositionsModel.ROLE_CHANGE_COLOR)
        if ccol == "chg":
            painter.setPen(QPen(Qt.darkGreen))
        elif ccol == "chr":
            painter.setPen(QPen(Qt.red))
        painter.setFont(orntnDelegate.getChangeFont())
        textRect.adjust(0, lineSp2 + self.MARGIN, 0, lineSp3 + self.MARGIN)
        painter.drawText(textRect, Qt.AlignTop | Qt.AlignLeft, line3)

        '''
        Right Column
        '''

        orntnDelegate.paintRightCol(index, painter, rightColRect)

        painter.setPen(borderPen)
        painter.drawRect(itemRect)

        painter.restore()