blob: ac381472565efbf6d5ac91390d32c4a1f17d36d8 [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>
Olivier SOLDANOc6425d32017-04-26 16:53:12 -040025#include <QDebug>
Edric Milareted0b2802015-10-01 15:10:02 -040026
Olivier SOLDANOc6425d32017-04-26 16:53:12 -040027// LRC
Edric Milareted0b2802015-10-01 15:10:02 -040028#include "itemdataroles.h"
29#include "person.h"
30#include "recentmodel.h"
31#include "call.h"
Olivier SOLDANOc6425d32017-04-26 16:53:12 -040032
33// Client
Nicolas Jager389a2292016-02-03 12:30:09 -050034#include "combar.h"
Edric Milareted0b2802015-10-01 15:10:02 -040035
Edric Milaret4e370992016-01-20 11:29:32 -050036#include "ringthemeutils.h"
37
Nicolas Jager97a21b42015-12-03 16:55:45 -050038SmartListDelegate::SmartListDelegate(QObject* parent) :
Edric Milareta0ebd062016-01-13 12:18:23 -050039 QItemDelegate(parent)
Edric Milareted0b2802015-10-01 15:10:02 -040040{
Edric Milareted0b2802015-10-01 15:10:02 -040041}
42
43void
Nicolas Jager97a21b42015-12-03 16:55:45 -050044SmartListDelegate::paint(QPainter* painter
45 , const QStyleOptionViewItem& option
46 , const QModelIndex& index
47 ) const
Edric Milareted0b2802015-10-01 15:10:02 -040048{
Nicolas Jager97a21b42015-12-03 16:55:45 -050049 QStyleOptionViewItem opt(option);
Edric Milareta13b48c2016-01-18 14:42:35 -050050 painter->setRenderHint(QPainter::Antialiasing);
Edric Milaret645e4c32016-01-18 15:55:08 -050051
Anthony Léonard522c2f12017-04-21 10:59:06 -040052 // Not having focus removes dotted lines around the item
53 if (opt.state & QStyle::State_HasFocus)
54 opt.state ^= QStyle::State_HasFocus;
55
56 // First, we draw the control itself
57 QStyle* style = opt.widget ? opt.widget->style() : QApplication::style();
58 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
59
60 QRect &rect = opt.rect;
61
62 // Avatar drawing
Edric Milareta13b48c2016-01-18 14:42:35 -050063 opt.decorationSize = QSize(sizeImage_, sizeImage_);
Edric Milareta0ebd062016-01-13 12:18:23 -050064 opt.decorationPosition = QStyleOptionViewItem::Left;
65 opt.decorationAlignment = Qt::AlignCenter;
Edric Milaret645e4c32016-01-18 15:55:08 -050066
Edric Milareta0ebd062016-01-13 12:18:23 -050067 QRect rectAvatar(16 + rect.left(), rect.top() + dy_, sizeImage_, sizeImage_);
Edric Milaret645e4c32016-01-18 15:55:08 -050068 drawDecoration(painter, opt, rectAvatar,
69 QPixmap::fromImage(index.data(Qt::DecorationRole).value<QImage>()));
Nicolas Jager97a21b42015-12-03 16:55:45 -050070
Edric Milareta0ebd062016-01-13 12:18:23 -050071 QFont font(painter->font());
Edric Milaret23fd3fa2016-01-15 15:37:35 -050072
Anthony Léonard522c2f12017-04-21 10:59:06 -040073 // If there's unread messages, a message count is displayed
Edric Milaret23fd3fa2016-01-15 15:37:35 -050074 if (auto messageCount = index.data(static_cast<int>(Ring::Role::UnreadTextMessageCount)).toInt()) {
Edric Milaret23fd3fa2016-01-15 15:37:35 -050075 font.setPointSize(8);
76 QFontMetrics textFontMetrics(font);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050077
Anthony Léonard522c2f12017-04-21 10:59:06 -040078 // If there is more than 10 unread messages, "10+" is displayed
Olivier SOLDANOb1f651e2017-07-13 16:24:56 -040079 QString messageCountText = (messageCount >= 10)? "9+" : QString::number(messageCount);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050080
Anthony Léonard522c2f12017-04-21 10:59:06 -040081 // This QRect is the bounding one containing the message count to be displayed
Olivier SOLDANOb1f651e2017-07-13 16:24:56 -040082 QRect pastilleRect = textFontMetrics.boundingRect(QRect(rectAvatar.left() - (2 * sizeImage_)/9,
83 rectAvatar.bottom() - sizeImage_/3 - textFontMetrics.height(), sizeImage_, textFontMetrics.height()),
84 Qt::AlignVCenter | Qt::AlignLeft, messageCountText);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050085
Anthony Léonard522c2f12017-04-21 10:59:06 -040086 // This one is larger than pastilleRect and is used to prepare the red background
87 QRect bubbleRect(pastilleRect.left() - 3, pastilleRect.top(),
88 pastilleRect.width() + 6, pastilleRect.height() + 1);
89
90 // The background is displayed
Edric Milaret23fd3fa2016-01-15 15:37:35 -050091 QPainterPath path;
92 path.addRoundedRect(bubbleRect, 3, 3);
Edric Milaret4e370992016-01-20 11:29:32 -050093 QPen pen(RingTheme::red_, 5);
Anthony Léonard522c2f12017-04-21 10:59:06 -040094 painter->setOpacity(0.9);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050095 painter->setPen(pen);
Edric Milaret4e370992016-01-20 11:29:32 -050096 painter->fillPath(path, RingTheme::red_);
Edric Milaret23fd3fa2016-01-15 15:37:35 -050097
Anthony Léonard522c2f12017-04-21 10:59:06 -040098 // Then the message count
Edric Milaret23fd3fa2016-01-15 15:37:35 -050099 painter->setPen(Qt::white);
100 painter->setOpacity(1);
101 painter->setFont(font);
Anthony Léonard522c2f12017-04-21 10:59:06 -0400102 painter->drawText(pastilleRect, Qt::AlignCenter, messageCountText);
Edric Milaret23fd3fa2016-01-15 15:37:35 -0500103 }
Nicolas Jager97a21b42015-12-03 16:55:45 -0500104
Anthony Léonarda8d78f92017-04-28 11:40:29 -0400105 // Presence indicator
106 QPainterPath outerCircle, innerCircle;
Olivier SOLDANOb1f651e2017-07-13 16:24:56 -0400107 QPointF center(rectAvatar.right() - sizeImage_/6, (rectAvatar.bottom() - sizeImage_/6) + 1);
Anthony Léonarda8d78f92017-04-28 11:40:29 -0400108 qreal outerCRadius = sizeImage_ / 6, innerCRadius = outerCRadius * 0.75;
109 outerCircle.addEllipse(center, outerCRadius, outerCRadius);
110 innerCircle.addEllipse(center, innerCRadius, innerCRadius);
111 if (index.data(static_cast<int>(Ring::Role::IsPresent)).value<bool>()) {
112 painter->fillPath(outerCircle, Qt::white);
113 painter->fillPath(innerCircle, RingTheme::green_);
114 }
Anthony Léonard522c2f12017-04-21 10:59:06 -0400115 font.setPointSize(fontSize_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500116 QPen pen(painter->pen());
Edric Milareta0ebd062016-01-13 12:18:23 -0500117
Anthony Léonard522c2f12017-04-21 10:59:06 -0400118 // A lightGrey separator is painted at the bottom if the current item is not selected
Edric Milareta0ebd062016-01-13 12:18:23 -0500119 if (not (opt.state & QStyle::State_Selected)) {
Edric Milaret4e370992016-01-20 11:29:32 -0500120 pen.setColor(RingTheme::lightGrey_);
Edric Milareta0ebd062016-01-13 12:18:23 -0500121 painter->setPen(pen);
122 painter->drawLine(rect.left() + 20, rect.bottom(),
123 rect.right() - 20,
124 rect.bottom());
125 }
Anthony Léonard522c2f12017-04-21 10:59:06 -0400126
Nicolas Jager97a21b42015-12-03 16:55:45 -0500127 if (index.column() == 0)
128 {
129 painter->setPen(pen);
130
Anthony Léonard522c2f12017-04-21 10:59:06 -0400131 QRect rectTexts(16 + rect.left() + dx_ + sizeImage_,
132 rect.top(),
133 rect.width(),
134 rect.height() / 2);
135
Olivier SOLDANOc6425d32017-04-26 16:53:12 -0400136 // The name is displayed at the avatar's right
Edric Milareted0b2802015-10-01 15:10:02 -0400137 QVariant name = index.data(static_cast<int>(Ring::Role::Name));
Nicolas Jager97a21b42015-12-03 16:55:45 -0500138 if (name.isValid())
139 {
Edric Milaret4e370992016-01-20 11:29:32 -0500140 pen.setColor(RingTheme::lightBlack_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500141 painter->setPen(pen);
142 font.setBold(true);
143 painter->setFont(font);
Edric Milaret645e4c32016-01-18 15:55:08 -0500144 QFontMetrics fontMetrics(font);
Nicolas Jager389a2292016-02-03 12:30:09 -0500145 QString nameStr = fontMetrics.elidedText(name.toString(), Qt::ElideRight
146 , rectTexts.width()- sizeImage_ - effectiveComBarSize_ - dx_);
Olivier SOLDANOc6425d32017-04-26 16:53:12 -0400147 painter->drawText(rectTexts, Qt::AlignVCenter | Qt::AlignLeft, nameStr);
148 }
149
150 // Display the ID under the name
Olivier SOLDANO31b9aac2017-07-14 15:50:09 -0400151 QString idStr = index.data(static_cast<int>(Ring::Role::Number)).value<QString>();
Olivier SOLDANOc6425d32017-04-26 16:53:12 -0400152 pen.setColor(RingTheme::grey_);
153 painter->setPen(pen);
154 font.setItalic(true);
155 font.setBold(false);
156 painter->setFont(font);
157 QFontMetrics fontMetrics(font);
158 if (!idStr.isNull()){
159 idStr = fontMetrics.elidedText(idStr, Qt::ElideRight, rectTexts.width()- sizeImage_ - effectiveComBarSize_ - dx_);
160 painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_,
161 rect.top() + rect.height()/7,
162 rect.width(),
163 rect.height()/2),
164 Qt::AlignBottom | Qt::AlignLeft, idStr);
165
166 } else {
167 qDebug() << "This is not a Person";
Edric Milareted0b2802015-10-01 15:10:02 -0400168 }
169
Anthony Léonard522c2f12017-04-21 10:59:06 -0400170 // Finally, either last interaction date or call state is displayed
Edric Milareted0b2802015-10-01 15:10:02 -0400171 QVariant state = index.data(static_cast<int>(Ring::Role::FormattedState));
Edric Milaret4e370992016-01-20 11:29:32 -0500172 pen.setColor(RingTheme::grey_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500173 painter->setPen(pen);
Olivier SOLDANOc6425d32017-04-26 16:53:12 -0400174 font.setItalic(false);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500175 font.setBold(false);
176 painter->setFont(font);
177 rectTexts.moveTop(cellHeight_/2);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500178 if (state.isValid() && RecentModel::instance().getActiveCall(RecentModel::instance().peopleProxy()->mapToSource(index)))
179 {
Edric Milareta0ebd062016-01-13 12:18:23 -0500180 painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_,
Olivier SOLDANOc6425d32017-04-26 16:53:12 -0400181 rect.top() + rect.height()/2,
182 rect.width(),
183 rect.height()/2),
184 Qt::AlignLeft | Qt::AlignVCenter, state.toString());
Nicolas Jager97a21b42015-12-03 16:55:45 -0500185 }
186 else
187 {
Edric Milareted0b2802015-10-01 15:10:02 -0400188 QVariant lastUsed = index.data(static_cast<int>(Ring::Role::FormattedLastUsed));
Nicolas Jager97a21b42015-12-03 16:55:45 -0500189 if (lastUsed.isValid())
190 {
Edric Milareta0ebd062016-01-13 12:18:23 -0500191 painter->drawText(QRect(16 + rect.left() + dx_ + sizeImage_,
Olivier SOLDANOc6425d32017-04-26 16:53:12 -0400192 rect.top() + rect.height()/2,
193 rect.width(),
194 rect.height()/2),
195 Qt::AlignLeft | Qt::AlignVCenter, lastUsed.toString());
Edric Milareted0b2802015-10-01 15:10:02 -0400196 }
197 }
Nicolas Jager97a21b42015-12-03 16:55:45 -0500198 }
199 else
200 {
Edric Milareta0ebd062016-01-13 12:18:23 -0500201 QItemDelegate::paint(painter, opt, index);
Edric Milareted0b2802015-10-01 15:10:02 -0400202 }
203}
204
205QSize
Nicolas Jager97a21b42015-12-03 16:55:45 -0500206SmartListDelegate::sizeHint(const QStyleOptionViewItem& option
207 , const QModelIndex& index
208 ) const
Edric Milareted0b2802015-10-01 15:10:02 -0400209{
Edric Milareta0ebd062016-01-13 12:18:23 -0500210 QSize size = QItemDelegate::sizeHint(option, index);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500211 size.setHeight(cellHeight_);
Nicolas Jager97a21b42015-12-03 16:55:45 -0500212 return size;
213}