def paintSection(self, painter, rect, logicalIndex): """ Re-implementation of QHeaderView.paintSection() to deal with multi-sorting. """ if not rect.isValid(): return painter.save() # get the state of the section opt = QtGui.QStyleOptionHeader() self.initStyleOption(opt) state = QtGui.QStyle.State_None if self.isEnabled(): state |= QtGui.QStyle.State_Enabled if self.window().isActiveWindow(): state |= QtGui.QStyle.State_Active # store some frequently used objects setOptBrush = opt.palette.setBrush getHeaderData = self.model().headerData palette = self.palette() orientation = self.orientation() # set up sorted column headers sortColumns = self.model().sorter.sortColumns sortDirections = self.model().sorter.sortDirections sortIndex = -1 if self.isSortIndicatorShown(): try: sortIndex = sortColumns.index(logicalIndex) except ValueError: pass # this column is not a part of the multi-sort if sortIndex >= 0: opt.sortIndicator = QtGui.QStyleOptionHeader.SortDown if sortDirections[ sortIndex] == QtCore.Qt.AscendingOrder else QtGui.QStyleOptionHeader.SortUp # paint sorted column slightly darker than normal setOptBrush(QtGui.QPalette.Button, QtGui.QBrush(palette.button().color().darker(110))) setOptBrush(QtGui.QPalette.Window, QtGui.QBrush(palette.window().color().darker(110))) setOptBrush(QtGui.QPalette.Dark, QtGui.QBrush(palette.dark().color().darker(110))) # setup the style options structure opt.rect = rect opt.section = logicalIndex opt.state |= state opt.text = getHeaderData(logicalIndex, orientation, QtCore.Qt.DisplayRole) textAlignment = getHeaderData(logicalIndex, orientation, QtCore.Qt.TextAlignmentRole) opt.textAlignment = QtCore.Qt.Alignment( textAlignment if textAlignment is not None else self. defaultAlignment()) opt.iconAlignment = QtCore.Qt.AlignVCenter if self.textElideMode() != QtCore.Qt.ElideNone: opt.text = opt.fontMetrics.elidedText(opt.text, self.textElideMode(), rect.width() - 4) icon = getHeaderData(logicalIndex, orientation, QtCore.Qt.DecorationRole) if icon: opt.icon = icon foregroundBrush = getHeaderData(logicalIndex, orientation, QtCore.Qt.ForegroundRole) if foregroundBrush: setOptBrush(QtGui.QPalette.ButtonText, foregroundBrush) backgroundBrush = getHeaderData(logicalIndex, orientation, QtCore.Qt.BackgroundRole) if backgroundBrush: setOptBrush(QtGui.QPalette.Button, backgroundBrush) setOptBrush(QtGui.QPalette.Window, backgroundBrush) painter.setBrushOrigin(opt.rect.topLeft()) # determine column position visual = self.visualIndex(logicalIndex) assert visual != -1 if self.count() == 1: opt.position = QtGui.QStyleOptionHeader.OnlyOneSection elif visual == 0: opt.position = QtGui.QStyleOptionHeader.Beginning elif visual == self.count() - 1: opt.position = QtGui.QStyleOptionHeader.End else: opt.position = QtGui.QStyleOptionHeader.Middle opt.orientation = orientation # draw the section self.style().drawControl(QtGui.QStyle.CE_Header, opt, painter, self) painter.restore() # darken if it is a locked column in the view if not self.__columnIsUnlocked(logicalIndex): painter.fillRect(rect, QtGui.QColor(0, 0, 0, 40)) # paint a number overlay when multi-sorting if sortIndex >= 0 and len(sortColumns) > 1: # paint a number indicator when multi-sorting text = str(sortIndex + 1) headerFont = QtGui.QFont(painter.font()) headerFont.setPointSize(headerFont.pointSize() - 2) textWidth = QtGui.QFontMetrics(headerFont).boundingRect( text).width() # calculate the indicator location point = QtCore.QPointF(rect.bottomRight()) point.setX(point.x() - textWidth - 1) point.setY(point.y() - 1) # paint the number overlay painter.save() painter.setCompositionMode(QtGui.QPainter.CompositionMode_Source) painter.setFont(headerFont) painter.drawText(point, text) painter.restore()
def initStyleOption(self, option, index, model=None, dataType=None): """ Initialize <option> with the values using the index <index>. :parameters: option : QtGui.QStyleOption style information index : QtCore.QModelIndex index if the cell to draw """ # TODO: speed this up further, by caching more? QtGui.QStyledItemDelegate.initStyleOption(self, option, index) editBitMask = 0 if model is None: model = index.model() column = index.column() item = None if model: item = model.itemFromIndex(index) if dataType is None: dataType = model.dataType(index) if model.isEditMode: # get the edit type for this column if item: editBitMask = item.editBitMask(index.column()) # border color option.borderColor = self._getBorderColor(option, index) # catch qvariants isError, bgrole, fgrole = item.getStyleData(column) if common.IS_PYQT_SIP1: isError = not isError.isNull() # background color bgColor = None # text color fgColor = None if isError: # errored items bgColor = ERRORBGCOLOUR fgColor = ERRORFGCOLOUR elif editBitMask: # model is in edit mode and cell has edits, paint # background based on edit type editName = common.getEditName(editBitMask) bgColor = theme.getIvyEditColour(editName, foreground=False) fgColor = theme.getIvyEditColour(editName) else: if bgrole: bgColor = QtGui.QColor(bgrole) else: bgColor = self._getBackgroundColor(option, index) if fgrole: fgColor = QtGui.QColor(fgrole) else: fgColor = self._getForegroundColor(option, index) # overlay the custom background color if isinstance(bgColor, QtGui.QColor) and bgColor.isValid(): option.backgroundBrush = QtGui.QBrush(bgColor) if isinstance(fgColor, QtGui.QColor) and fgColor.isValid(): option.palette.setColor(QtGui.QPalette.Text, fgColor) # text font font = None if editBitMask: if editBitMask & common.EDITBITMASK_DELETE: # use strikethrough with deletion edits font = option.font font.setStrikeOut(True) else: font = self._getFont(option, index) # why is instance? why not is not None? if isinstance(font, QtGui.QFont): option.font = font # alignment if dataType in INT_TYPES: option.displayAlignment = QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter # set display text if model: displayText = self._displayText(index, dataType) if displayText is not None: if hasattr(option, "features"): option.features |= QtGui.QStyleOptionViewItemV2.HasDisplay option.text = displayText