File indexing completed on 2023-05-30 09:18:55

0001 /*
0002  * Abstract Contact Delegate - base class for other delegates
0003  *
0004  * Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library; if not, write to the Free Software
0018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0019  */
0020 
0021 #include "abstract-contact-delegate.h"
0022 
0023 #include <QApplication>
0024 #include <QStyle>
0025 #include <QPainter>
0026 #include <QToolTip>
0027 #include <QHelpEvent>
0028 #include <QFontDatabase>
0029 #include <QAbstractItemView>
0030 #include <QStyleOptionViewItem>
0031 
0032 #include <KIconLoader>
0033 
0034 #include <KTp/types.h>
0035 
0036 const int SPACING = 2;
0037 const int ACCOUNT_ICON_SIZE = 22;
0038 const qreal GROUP_ICON_OPACITY = 0.6;
0039 
0040 AbstractContactDelegate::AbstractContactDelegate(QObject *parent)
0041     : QStyledItemDelegate(parent)
0042 {
0043 }
0044 
0045 AbstractContactDelegate::~AbstractContactDelegate()
0046 {
0047 }
0048 
0049 void AbstractContactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0050 {
0051     if (index.data(KTp::RowTypeRole).toInt() == KTp::ContactRowType || index.data(KTp::RowTypeRole).toInt() == KTp::PersonRowType) {
0052         paintContact(painter, option, index);
0053     } else {
0054         paintHeader(painter, option, index);
0055     }
0056 }
0057 
0058 QSize AbstractContactDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
0059 {
0060     if (index.data(KTp::RowTypeRole).toInt() == KTp::ContactRowType || index.data(KTp::RowTypeRole).toInt() == KTp::PersonRowType) {
0061         return sizeHintContact(option, index);
0062     } else {
0063         return sizeHintHeader(option, index);
0064     }
0065 }
0066 
0067 void AbstractContactDelegate::paintHeader(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0068 {
0069     QStyleOptionViewItem opt = option;
0070     initStyleOption(&opt, index);
0071 
0072     painter->save();
0073 
0074     painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing);
0075     painter->setClipRect(opt.rect);
0076 
0077     QStyle *style = QApplication::style();
0078     style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
0079 
0080     QRect groupRect = opt.rect;
0081 
0082     //paint the background
0083     QBrush bgBrush(option.palette.color(QPalette::Active, QPalette::Button).lighter(105));
0084     painter->fillRect(groupRect, bgBrush);
0085 
0086     //paint very subtle line at the bottom
0087     QPen thinLinePen;
0088     thinLinePen.setWidth(0);
0089     thinLinePen.setColor(option.palette.color(QPalette::Active, QPalette::Button));
0090     painter->setPen(thinLinePen);
0091     //to get nice sharp 1px line we need to turn AA off, otherwise it will be all blurry
0092     painter->setRenderHint(QPainter::Antialiasing, false);
0093     painter->drawLine(groupRect.bottomLeft(), groupRect.bottomRight());
0094     painter->setRenderHint(QPainter::Antialiasing, true);
0095 
0096     //remove spacing from the sides and one point to the bottom for the 1px line
0097     groupRect.adjust(SPACING, 0, -SPACING, -1);
0098 
0099     //get the proper rect for the expand sign
0100     int iconSize = IconSize(KIconLoader::Toolbar);
0101 
0102     QStyleOption expandSignOption = option;
0103     expandSignOption.rect = groupRect;
0104     //FIXME hardcoded magic...though corresponds with the list indentation
0105     expandSignOption.rect.setSize(QSize(14, iconSize));
0106     expandSignOption.rect.moveLeft(groupRect.left());
0107     expandSignOption.rect.moveTop(groupRect.top() + groupRect.height()/2 - expandSignOption.rect.height()/2);
0108     // simulates mouseover to highlight arrow when selected with keyboard
0109     if (option.state & QStyle::State_Selected) {
0110         expandSignOption.state |= QStyle::State_MouseOver;
0111     }
0112 
0113     //paint the expand sign
0114     if (option.state & QStyle::State_Open) {
0115         style->drawPrimitive(QStyle::PE_IndicatorArrowDown, &expandSignOption, painter);
0116     } else {
0117         style->drawPrimitive(QStyle::PE_IndicatorArrowRight, &expandSignOption, painter);
0118     }
0119 
0120     QFont groupFont = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont);
0121 
0122     //paint the group icon
0123     QRect groupIconRect;
0124     groupIconRect.setSize(QSize(ACCOUNT_ICON_SIZE, ACCOUNT_ICON_SIZE));
0125     groupIconRect.moveRight(groupRect.right());
0126     groupIconRect.moveTop(groupRect.top() + groupRect.height()/2 - groupIconRect.height()/2);
0127 
0128     if (index.data(KTp::RowTypeRole).toInt() == KTp::AccountRowType) {
0129         //draw the icon with some opacity
0130         painter->setOpacity(GROUP_ICON_OPACITY);
0131         painter->drawPixmap(groupIconRect, index.data(Qt::DecorationRole).value<QIcon>().pixmap(ACCOUNT_ICON_SIZE));
0132         painter->setOpacity(1.0);
0133     } else {
0134         groupIconRect.setWidth(0);
0135     }
0136 
0137     //paint the header string
0138     QRect groupLabelRect = groupRect.adjusted(expandSignOption.rect.width() + SPACING * 2, 0, -groupIconRect.width() -SPACING, 0);
0139     QString countsString = QString("(%1/%2)").arg(index.data(KTp::HeaderOnlineUsersRole).toString(),
0140                                                   index.data(KTp::HeaderTotalUsersRole).toString());
0141     QString groupHeaderString =  index.data(Qt::DisplayRole).toString();
0142     QFontMetrics groupFontMetrics(groupFont);
0143 
0144     painter->setFont(groupFont);
0145     if (index.data(KTp::HeaderTotalUsersRole).toInt() > 0) {
0146         painter->setPen(option.palette.color(QPalette::Disabled, QPalette::Text));
0147         painter->drawText(groupLabelRect, Qt::AlignVCenter | Qt::AlignRight, countsString);
0148     }
0149 
0150     painter->setPen(option.palette.color(QPalette::Active, QPalette::Text));
0151     painter->drawText(groupLabelRect, Qt::AlignVCenter | Qt::AlignLeft,
0152                       groupFontMetrics.elidedText(groupHeaderString, Qt::ElideRight,
0153                                                   groupLabelRect.width() - groupFontMetrics.width(countsString) - SPACING));
0154 
0155     painter->restore();
0156 }
0157 
0158 QSize AbstractContactDelegate::sizeHintHeader(const QStyleOptionViewItem &option, const QModelIndex &index) const
0159 {
0160     Q_UNUSED(option)
0161     Q_UNUSED(index)
0162 
0163     // Add one point to the bottom for the 1px line
0164     return QSize(0, qMax(ACCOUNT_ICON_SIZE, QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont).pixelSize()) + SPACING + 1);
0165 }
0166 
0167 bool AbstractContactDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index)
0168 {
0169     Q_UNUSED(event)
0170     Q_UNUSED(view)
0171     Q_UNUSED(option)
0172     Q_UNUSED(index)
0173     return false;
0174 }
0175 
0176 void AbstractContactDelegate::avatarToGray(QPixmap &avatar) const
0177 {
0178     QImage image = avatar.toImage();
0179     QImage alpha= image.alphaChannel();
0180     for (int i = 0; i < image.width(); ++i) {
0181         for (int j = 0; j < image.height(); ++j) {
0182             int colour = qGray(image.pixel(i, j));
0183             image.setPixel(i, j, qRgb(colour, colour, colour));
0184         }
0185     }
0186     image.setAlphaChannel(alpha);
0187     avatar = QPixmap::fromImage(image);
0188 }