File indexing completed on 2022-11-29 14:16:03

0001 /*
0002  * Contact Delegate
0003  *
0004  * Copyright (C) 2010-2011 Collabora Ltd. <info@collabora.co.uk>
0005  *   @Author Dario Freddi <dario.freddi@collabora.co.uk>
0006  * Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
0007  * Copyright (C) 2012 Dominik Cermak <d.cermak@arcor.de>
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Lesser General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2.1 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Lesser General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Lesser General Public
0020  * License along with this library; if not, write to the Free Software
0021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0022  */
0023 
0024 #include "contact-delegate.h"
0025 
0026 #include <QPainter>
0027 #include <QPainterPath>
0028 #include <QApplication>
0029 #include <QFontDatabase>
0030 #include <QPixmapCache>
0031 #include <QStyle>
0032 #include <QStyleOptionViewItem>
0033 
0034 #include <KIconLoader>
0035 
0036 #include <KTp/types.h>
0037 #include <KTp/presence.h>
0038 
0039 ContactDelegate::ContactDelegate(QObject * parent)
0040     : AbstractContactDelegate(parent)
0041     , m_avatarSize(IconSize(KIconLoader::Dialog))
0042     , m_presenceIconSize(IconSize(KIconLoader::Toolbar))
0043     , m_spacing(IconSize(KIconLoader::Dialog) / 8)
0044 {
0045     QPixmapCache::setCacheLimit(102400);
0046 }
0047 
0048 ContactDelegate::~ContactDelegate()
0049 {
0050 
0051 }
0052 
0053 void ContactDelegate::paintContact(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0054 {
0055     QStyleOptionViewItem opt = option;
0056     initStyleOption(&opt, index);
0057 
0058     painter->save();
0059 
0060     painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::HighQualityAntialiasing);
0061     painter->setClipRect(opt.rect);
0062 
0063     QStyle *style = QApplication::style();
0064     style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
0065 
0066     QRect iconRect = opt.rect;
0067     iconRect.setSize(QSize(m_avatarSize, m_avatarSize));
0068     iconRect.moveTo(QPoint(iconRect.x() + m_spacing, iconRect.y() + m_spacing));
0069 
0070     QPixmap avatar(qvariant_cast<QPixmap>(index.data(KTp::ContactAvatarPixmapRole)));
0071     if (index.data(KTp::ContactUnreadMessageCountRole).toInt() > 0) {
0072         avatar = SmallIcon("mail-unread-new", KIconLoader::SizeMedium);
0073     }
0074 
0075     QPainterPath roundedPath;
0076     roundedPath.addRoundedRect(iconRect, 20, 20, Qt::RelativeSize);
0077 
0078     painter->save();
0079     painter->setClipPath(roundedPath);
0080 
0081     //if the contact is offline, gray it out
0082     if (index.data(KTp::ContactPresenceTypeRole).toUInt() == Tp::ConnectionPresenceTypeOffline) {
0083         if (!QPixmapCache::find(index.data(KTp::IdRole).toString() + QStringLiteral("gray"), &avatar)) {
0084             avatarToGray(avatar);
0085             QPixmapCache::insert(index.data(KTp::IdRole).toString() + QStringLiteral("gray"), avatar);
0086         }
0087     }
0088 
0089     if (!avatar.isNull()) {
0090         style->drawItemPixmap(painter, iconRect, Qt::AlignCenter, avatar.scaled(iconRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
0091     }
0092 
0093     painter->restore();
0094 
0095     QPen thinLinePen;
0096     thinLinePen.setWidth(0);
0097     thinLinePen.setColor(option.palette.color(QPalette::Disabled, QPalette::Text));
0098 
0099     painter->save();
0100 
0101     painter->setPen(thinLinePen);
0102     painter->setRenderHint(QPainter::Antialiasing, false);
0103     painter->drawPath(roundedPath);
0104 
0105     //clear the font and AA setting
0106     painter->restore();
0107 
0108     // This value is used to set the correct width for the username and the presence message.
0109     int rightIconsWidth = m_presenceIconSize + m_spacing;
0110 
0111     QPixmap icon = QIcon::fromTheme(index.data(KTp::ContactPresenceIconRole).toString()).pixmap(KIconLoader::SizeSmallMedium);
0112 
0113     QRect statusIconRect = opt.rect;
0114     statusIconRect.setSize(QSize(m_presenceIconSize, m_presenceIconSize));
0115     statusIconRect.moveTo(QPoint(opt.rect.right() - rightIconsWidth,
0116                                  opt.rect.top() + (opt.rect.height() - m_presenceIconSize) / 2));
0117 
0118     painter->drawPixmap(statusIconRect, icon);
0119 
0120     // Right now we only check for 'phone', as that's the most interesting type.
0121     if (index.data(KTp::ContactClientTypesRole).toStringList().contains(QLatin1String("phone"))) {
0122         // Additional space is needed for the icons, don't add too much spacing between the two icons
0123         rightIconsWidth += m_presenceIconSize + m_spacing / 2;
0124 
0125         QPixmap phone = QIcon::fromTheme("phone").pixmap(m_presenceIconSize);
0126         QRect phoneIconRect = opt.rect;
0127         phoneIconRect.setSize(QSize(m_presenceIconSize, m_presenceIconSize));
0128         phoneIconRect.moveTo(QPoint(opt.rect.right() - rightIconsWidth,
0129                                     opt.rect.top() + (opt.rect.height() - m_presenceIconSize) / 2));
0130         painter->drawPixmap(phoneIconRect, phone);
0131     }
0132 
0133     QRect userNameRect = opt.rect;
0134     userNameRect.setX(iconRect.x() + iconRect.width() + m_spacing);
0135     userNameRect.setY(userNameRect.y() + m_spacing / 2);
0136     userNameRect.setWidth(userNameRect.width() - rightIconsWidth);
0137 
0138     const QFontMetrics nameFontMetrics(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0139 
0140     if (option.state & QStyle::State_Selected) {
0141         painter->setPen(option.palette.color(option.palette.currentColorGroup(), QPalette::HighlightedText));
0142     } else {
0143         painter->setPen(option.palette.color(option.palette.currentColorGroup(), QPalette::Text));
0144     }
0145 
0146     painter->drawText(userNameRect,
0147                       nameFontMetrics.elidedText(opt.text, Qt::ElideRight, userNameRect.width()));
0148 
0149     const QFontMetrics statusFontMetrics(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0150 
0151     QRect statusMsgRect = opt.rect;
0152     statusMsgRect.setX(iconRect.x() + iconRect.width() + m_spacing);
0153     statusMsgRect.setY(userNameRect.bottom() - statusFontMetrics.height() - 4);
0154     statusMsgRect.setWidth(statusMsgRect.width() - rightIconsWidth);
0155 
0156     QColor fadingColor;
0157     if (option.state & QStyle::State_Selected) {
0158         fadingColor = QColor(option.palette.color(QPalette::Disabled, QPalette::HighlightedText));
0159     } else {
0160         fadingColor = QColor(option.palette.color(QPalette::Disabled, QPalette::Text));
0161     }
0162 
0163     // if the index is hovered, set animated alpha to the color
0164     if (index == m_indexForHiding) {
0165         fadingColor.setAlpha(m_fadingValue);
0166     }
0167 
0168     painter->setPen(fadingColor);
0169 
0170     painter->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0171     painter->drawText(statusMsgRect,
0172                       statusFontMetrics.elidedText(index.data(KTp::ContactPresenceMessageRole).toString().trimmed(),
0173                                                    Qt::ElideRight, statusMsgRect.width()));
0174 
0175     painter->restore();
0176 }
0177 
0178 QSize ContactDelegate::sizeHintContact(const QStyleOptionViewItem &option, const QModelIndex &index) const
0179 {
0180     Q_UNUSED(option);
0181     Q_UNUSED(index);
0182     return QSize(0, m_avatarSize + 2 * m_spacing);
0183 }
0184 
0185 void ContactDelegate::hideStatusMessageSlot(const QModelIndex& index)
0186 {
0187     m_indexForHiding = index;
0188     fadeOutStatusMessageSlot();
0189 }
0190 
0191 void ContactDelegate::reshowStatusMessageSlot()
0192 {
0193     m_fadingValue = 255;
0194     m_indexForHiding = QModelIndex();
0195     emit repaintItem(m_indexForHiding);
0196 }
0197 
0198 void ContactDelegate::fadeOutStatusMessageSlot()
0199 {
0200     QPropertyAnimation *a = new QPropertyAnimation(this, "m_fadingValue");
0201     a->setParent(this);
0202     a->setDuration(100);
0203     a->setEasingCurve(QEasingCurve::OutExpo);
0204     a->setStartValue(255);
0205     a->setEndValue(0);
0206     a->start();
0207 
0208     connect(a, SIGNAL(valueChanged(QVariant)),
0209             this, SLOT(triggerRepaint()));
0210 
0211     connect(a, SIGNAL(finished()),
0212             a, SLOT(deleteLater()));
0213 }
0214 
0215 int ContactDelegate::fadingValue() const
0216 {
0217     return m_fadingValue;
0218 }
0219 
0220 void ContactDelegate::setFadingValue(int value)
0221 {
0222     m_fadingValue = value;
0223 }
0224 
0225 void ContactDelegate::triggerRepaint()
0226 {
0227     emit repaintItem(m_indexForHiding);
0228 }