blob: e9411ed0bfe633a9ddb7bfc561a94c5461227f67 [file] [log] [blame]
Edric Milareted0b2802015-10-01 15:10:02 -04001/***************************************************************************
Anthony Léonard2fde81d2017-04-17 10:06:55 -04002 * Copyright (C) 2015-2017 by Savoir-faire Linux *
Edric Milareted0b2802015-10-01 15:10:02 -04003 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
19#include "smartlistdelegate.h"
20
21#include <QApplication>
22#include <QSortFilterProxyModel>
23#include <QPainter>
Edric Milareta0ebd062016-01-13 12:18:23 -050024#include <QPixmap>
Edric Milareted0b2802015-10-01 15:10:02 -040025
26#include "itemdataroles.h"
27#include "person.h"
28#include "recentmodel.h"
29#include "call.h"
Nicolas Jager389a2292016-02-03 12:30:09 -050030#include "combar.h"
Edric Milareted0b2802015-10-01 15:10:02 -040031
Edric Milaret4e370992016-01-20 11:29:32 -050032#include "ringthemeutils.h"
33
Nicolas Jager97a21b42015-12-03 16:55:45 -050034SmartListDelegate::SmartListDelegate(QObject* parent) :
Edric Milareta0ebd062016-01-13 12:18:23 -050035 QItemDelegate(parent)
Edric Milareted0b2802015-10-01 15:10:02 -040036{
Edric Milareted0b2802015-10-01 15:10:02 -040037}
38
39void
Nicolas Jager97a21b42015-12-03 16:55:45 -050040SmartListDelegate::paint(QPainter* painter
41 , const QStyleOptionViewItem& option
42 , const QModelIndex& index
43 ) const
Edric Milareted0b2802015-10-01 15:10:02 -040044{
Nicolas Jager97a21b42015-12-03 16:55:45 -050045 QStyleOptionViewItem opt(option);
Edric Milareta13b48c2016-01-18 14:42:35 -050046 painter->setRenderHint(QPainter::Antialiasing);
Edric Milaret645e4c32016-01-18 15:55:08 -050047
Anthony Léonard522c2f12017-04-21 10:59:06 -040048 // Not having focus removes dotted lines around the item
49 if (opt.state & QStyle::State_HasFocus)
50 opt.state ^= QStyle::State_HasFocus;
51
52 // First, we draw the control itself
53 QStyle* style = opt.widget ? opt.widget->style() : QApplication::style();
54 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
55
56 QRect &rect = opt.rect;
57
58 // Avatar drawing
Edric Milareta13b48c2016-01-18 14:42:35 -050059 opt.decorationSize = QSize(sizeImage_, sizeImage_);
Edric Milareta0ebd062016-01-13 12:18:23 -050060 opt.decorationPosition = QStyleOptionViewItem::Left;
61 opt.decorationAlignment = Qt::AlignCenter;
Edric Milaret645e4c32016-01-18 15:55:08 -050062
Edric Milareta0ebd062016-01-13 12:18:23 -050063 QRect rectAvatar(16 + rect.left(), rect.top() + dy_, sizeImage_, sizeImage_);
Edric Milaret645e4c32016-01-18 15:55:08 -050064 drawDecoration(painter, opt, rectAvatar,
65 QPixmap::fromImage(index.data(Qt::DecorationRole).value<QImage>()));
Nicolas Jager97a21b42015-12-03 16:55:45 -050066
Edric Milareta0ebd062016-01-13 12:18:23 -050067 QFont font(painter->font());
Edric Milaret23fd3fa2016-01-15 15:37:35 -050068
Anthony Léonard522c2f12017-04-21 10:59:06 -040069 // If there's unread messages, a message count is displayed
Edric Milaret23fd3fa2016-01-15 15:37:35 -050070 if (auto messageCount = index.data(static_cast<int>(Ring::Role::UnreadTextMessageCount)).toInt()) {
Edric Milaret23fd3fa2016-01-15 15:37:35 -050071 font.setPointSize(8);
72 QFontMetrics textFontMetrics(font);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050073
Anthony Léonard522c2f12017-04-21 10:59:06 -040074 // If there is more than 10 unread messages, "10+" is displayed
75 QString messageCountText = (messageCount > 10)? "10+" : QString::number(messageCount);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050076
Anthony Léonard522c2f12017-04-21 10:59:06 -040077 // This QRect is the bounding one containing the message count to be displayed
78 QRect pastilleRect = textFontMetrics.boundingRect(QRect(rectAvatar.left() + sizeImage_/3,
79 rectAvatar.bottom() - textFontMetrics.height(), sizeImage_, textFontMetrics.height()),
80 Qt::AlignCenter, messageCountText);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050081
Anthony Léonard522c2f12017-04-21 10:59:06 -040082 // This one is larger than pastilleRect and is used to prepare the red background
83 QRect bubbleRect(pastilleRect.left() - 3, pastilleRect.top(),
84 pastilleRect.width() + 6, pastilleRect.height() + 1);
85
86 // The background is displayed
Edric Milaret23fd3fa2016-01-15 15:37:35 -050087 QPainterPath path;
88 path.addRoundedRect(bubbleRect, 3, 3);
Edric Milaret4e370992016-01-20 11:29:32 -050089 QPen pen(RingTheme::red_, 5);
Anthony Léonard522c2f12017-04-21 10:59:06 -040090 painter->setOpacity(0.9);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050091 painter->setPen(pen);
Edric Milaret4e370992016-01-20 11:29:32 -050092 painter->fillPath(path, RingTheme::red_);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050093
Anthony Léonard522c2f12017-04-21 10:59:06 -040094 // Then the message count
Edric Milaret23fd3fa2016-01-15 15:37:35 -050095 painter->setPen(Qt::white);
96 painter->setOpacity(1);
97 painter->setFont(font);
Anthony Léonard522c2f12017-04-21 10:59:06 -040098 painter->drawText(pastilleRect, Qt::AlignCenter, messageCountText);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050099 }
Nicolas Jager97a21b42015-12-03 16:55:45 -0500100
Anthony Léonard522c2f12017-04-21 10:59:06 -0400101 font.setPointSize(fontSize_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500102 QPen pen(painter->pen());
Edric Milareta0ebd062016-01-13 12:18:23 -0500103
Anthony Léonard522c2f12017-04-21 10:59:06 -0400104 // A lightGrey separator is painted at the bottom if the current item is not selected
Edric Milareta0ebd062016-01-13 12:18:23 -0500105 if (not (opt.state & QStyle::State_Selected)) {
Edric Milaret4e370992016-01-20 11:29:32 -0500106 pen.setColor(RingTheme::lightGrey_);
Edric Milareta0ebd062016-01-13 12:18:23 -0500107 painter->setPen(pen);
108 painter->drawLine(rect.left() + 20, rect.bottom(),
109 rect.right() - 20,
110 rect.bottom());
111 }
Anthony Léonard522c2f12017-04-21 10:59:06 -0400112
Nicolas Jager97a21b42015-12-03 16:55:45 -0500113 if (index.column() == 0)
114 {
115 painter->setPen(pen);
116
Anthony Léonard522c2f12017-04-21 10:59:06 -0400117 QRect rectTexts(16 + rect.left() + dx_ + sizeImage_,
118 rect.top(),
119 rect.width(),
120 rect.height() / 2);
121
122 // The name is displayed at the avatar's left
Edric Milareted0b2802015-10-01 15:10:02 -0400123 QVariant name = index.data(static_cast<int>(Ring::Role::Name));
Nicolas Jager97a21b42015-12-03 16:55:45 -0500124 if (name.isValid())
125 {
Edric Milaret4e370992016-01-20 11:29:32 -0500126 pen.setColor(RingTheme::lightBlack_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500127 painter->setPen(pen);
128 font.setBold(true);
129 painter->setFont(font);
Edric Milaret645e4c32016-01-18 15:55:08 -0500130 QFontMetrics fontMetrics(font);
Nicolas Jager389a2292016-02-03 12:30:09 -0500131 QString nameStr = fontMetrics.elidedText(name.toString(), Qt::ElideRight
132 , rectTexts.width()- sizeImage_ - effectiveComBarSize_ - dx_);
Edric Milaret645e4c32016-01-18 15:55:08 -0500133 painter->drawText(rectTexts, Qt::AlignBottom | Qt::AlignLeft, nameStr);
Edric Milareted0b2802015-10-01 15:10:02 -0400134 }
135
Anthony Léonard522c2f12017-04-21 10:59:06 -0400136 // Finally, either last interaction date or call state is displayed
Edric Milareted0b2802015-10-01 15:10:02 -0400137 QVariant state = index.data(static_cast<int>(Ring::Role::FormattedState));
Edric Milaret4e370992016-01-20 11:29:32 -0500138 pen.setColor(RingTheme::grey_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500139 painter->setPen(pen);
140 font.setBold(false);
141 painter->setFont(font);
142 rectTexts.moveTop(cellHeight_/2);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500143 if (state.isValid() && RecentModel::instance().getActiveCall(RecentModel::instance().peopleProxy()->mapToSource(index)))
144 {
Edric Milareta0ebd062016-01-13 12:18:23 -0500145 painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_,
Nicolas Jager97a21b42015-12-03 16:55:45 -0500146 rect.top() + rect.height()/2,
147 rect.width(), rect.height()/2),
148 Qt::AlignTop | Qt::AlignLeft, state.toString());
149 }
150 else
151 {
Edric Milareted0b2802015-10-01 15:10:02 -0400152 QVariant lastUsed = index.data(static_cast<int>(Ring::Role::FormattedLastUsed));
Nicolas Jager97a21b42015-12-03 16:55:45 -0500153 if (lastUsed.isValid())
154 {
Edric Milareta0ebd062016-01-13 12:18:23 -0500155 painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_,
Nicolas Jager97a21b42015-12-03 16:55:45 -0500156 rect.top() + rect.height()/2,
157 rect.width(), rect.height()/2),
158 Qt::AlignTop | Qt::AlignLeft, lastUsed.toString());
Edric Milareted0b2802015-10-01 15:10:02 -0400159 }
160 }
Nicolas Jager97a21b42015-12-03 16:55:45 -0500161 }
162 else
163 {
Edric Milareta0ebd062016-01-13 12:18:23 -0500164 QItemDelegate::paint(painter, opt, index);
Edric Milareted0b2802015-10-01 15:10:02 -0400165 }
166}
167
168QSize
Nicolas Jager97a21b42015-12-03 16:55:45 -0500169SmartListDelegate::sizeHint(const QStyleOptionViewItem& option
170 , const QModelIndex& index
171 ) const
Edric Milareted0b2802015-10-01 15:10:02 -0400172{
Edric Milareta0ebd062016-01-13 12:18:23 -0500173 QSize size = QItemDelegate::sizeHint(option, index);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500174 size.setHeight(cellHeight_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500175 return size;
176}